summaryrefslogtreecommitdiff
path: root/simulator/opendc-compute
diff options
context:
space:
mode:
Diffstat (limited to 'simulator/opendc-compute')
-rw-r--r--simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt5
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts1
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt188
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt103
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHostProvisioner.kt69
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt8
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt92
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt18
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt81
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/power/CpuPowerModelTest.kt22
10 files changed, 88 insertions, 499 deletions
diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt
index 2cd91144..060c35fd 100644
--- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt
+++ b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt
@@ -51,6 +51,11 @@ public interface Host {
public val state: HostState
/**
+ * Meta-data associated with the host.
+ */
+ public val meta: Map<String, Any>
+
+ /**
* The events emitted by the driver.
*/
public val events: Flow<HostEvent>
diff --git a/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts b/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts
index d7d5f002..31fcda2f 100644
--- a/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts
+++ b/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts
@@ -31,7 +31,6 @@ plugins {
dependencies {
api(platform(project(":opendc-platform")))
api(project(":opendc-compute:opendc-compute-service"))
- api(project(":opendc-metal"))
api(project(":opendc-simulator:opendc-simulator-compute"))
api(project(":opendc-simulator:opendc-simulator-failures"))
implementation(project(":opendc-utils"))
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt
deleted file mode 100644
index 2405a8f9..00000000
--- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.compute.simulator
-
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.Flow
-import org.opendc.compute.api.Flavor
-import org.opendc.compute.api.Image
-import org.opendc.compute.simulator.power.api.CpuPowerModel
-import org.opendc.compute.simulator.power.api.Powerable
-import org.opendc.compute.simulator.power.models.ConstantPowerModel
-import org.opendc.metal.Node
-import org.opendc.metal.NodeEvent
-import org.opendc.metal.NodeState
-import org.opendc.metal.driver.BareMetalDriver
-import org.opendc.simulator.compute.SimBareMetalMachine
-import org.opendc.simulator.compute.SimMachineModel
-import org.opendc.simulator.compute.workload.SimWorkload
-import org.opendc.simulator.failures.FailureDomain
-import org.opendc.utils.flow.EventFlow
-import org.opendc.utils.flow.StateFlow
-import java.time.Clock
-import java.util.UUID
-
-/**
- * A basic implementation of the [BareMetalDriver] that simulates an [Image] running on a bare-metal machine.
- *
- * @param coroutineScope The [CoroutineScope] the driver runs in.
- * @param clock The virtual clock to keep track of time.
- * @param uid The unique identifier of the machine.
- * @param name An optional name of the machine.
- * @param metadata The initial metadata of the node.
- * @param machine The machine model to simulate.
- * @param cpuPowerModel The CPU power model of this machine.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-public class SimBareMetalDriver(
- private val coroutineScope: CoroutineScope,
- private val clock: Clock,
- uid: UUID,
- name: String,
- metadata: Map<String, Any>,
- machine: SimMachineModel,
- cpuPowerModel: CpuPowerModel = ConstantPowerModel(0.0),
-) : BareMetalDriver, FailureDomain, Powerable {
- /**
- * The flavor that corresponds to this machine.
- */
- private val flavor = Flavor(
- machine.cpus.size,
- machine.memory.map { it.size }.sum()
- )
-
- /**
- * The events of the machine.
- */
- private val events = EventFlow<NodeEvent>()
-
- /**
- * The machine state.
- */
- private val nodeState =
- StateFlow(Node(uid, name, metadata + ("driver" to this), NodeState.SHUTOFF, flavor, Image.EMPTY, events))
-
- /**
- * The [SimBareMetalMachine] we use to run the workload.
- */
- private val machine = SimBareMetalMachine(coroutineScope, clock, machine)
-
- override val node: Flow<Node> = nodeState
-
- override val usage: Flow<Double>
- get() = this.machine.usage
-
- override val powerDraw: Flow<Double> = cpuPowerModel.getPowerDraw(this)
-
- /**
- * The [Job] that runs the simulated workload.
- */
- private var job: Job? = null
-
- override suspend fun init(): Node {
- return nodeState.value
- }
-
- override suspend fun start(): Node {
- val node = nodeState.value
- if (node.state != NodeState.SHUTOFF) {
- return node
- }
-
- val workload = node.image.tags["workload"] as SimWorkload
-
- job = coroutineScope.launch {
- delay(1) // TODO Introduce boot time
- initMachine()
- try {
- machine.run(workload, mapOf("driver" to this@SimBareMetalDriver, "node" to node))
- exitMachine(null)
- } catch (_: CancellationException) {
- // Ignored
- } catch (cause: Throwable) {
- exitMachine(cause)
- }
- }
-
- setNode(node.copy(state = NodeState.BOOT))
- return nodeState.value
- }
-
- private fun initMachine() {
- setNode(nodeState.value.copy(state = NodeState.ACTIVE))
- }
-
- private fun exitMachine(cause: Throwable?) {
- val newNodeState =
- if (cause == null)
- NodeState.SHUTOFF
- else
- NodeState.ERROR
- setNode(nodeState.value.copy(state = newNodeState))
- }
-
- override suspend fun stop(): Node {
- val node = nodeState.value
- if (node.state == NodeState.SHUTOFF) {
- return node
- }
-
- job?.cancelAndJoin()
- setNode(node.copy(state = NodeState.SHUTOFF))
- return node
- }
-
- override suspend fun reboot(): Node {
- stop()
- return start()
- }
-
- override suspend fun setImage(image: Image): Node {
- setNode(nodeState.value.copy(image = image))
- return nodeState.value
- }
-
- override suspend fun refresh(): Node = nodeState.value
-
- private fun setNode(value: Node) {
- val field = nodeState.value
- if (field.state != value.state) {
- events.emit(NodeEvent.StateChanged(value, field.state))
- }
-
- nodeState.value = value
- }
-
- override val scope: CoroutineScope
- get() = coroutineScope
-
- override suspend fun fail() {
- setNode(nodeState.value.copy(state = NodeState.ERROR))
- }
-
- override suspend fun recover() {
- setNode(nodeState.value.copy(state = NodeState.ACTIVE))
- }
-
- override fun toString(): String = "SimBareMetalDriver(node = ${nodeState.value.uid})"
-}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
index fd547d3d..e2d70dce 100644
--- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
@@ -29,34 +29,43 @@ import org.opendc.compute.api.Flavor
import org.opendc.compute.api.Server
import org.opendc.compute.api.ServerState
import org.opendc.compute.service.driver.*
-import org.opendc.metal.Node
+import org.opendc.compute.simulator.power.api.CpuPowerModel
+import org.opendc.compute.simulator.power.api.Powerable
+import org.opendc.compute.simulator.power.models.ConstantPowerModel
import org.opendc.simulator.compute.*
import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL
import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.workload.SimResourceCommand
import org.opendc.simulator.compute.workload.SimWorkload
+import org.opendc.simulator.failures.FailureDomain
import org.opendc.utils.flow.EventFlow
+import java.time.Clock
import java.util.*
+import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.resume
/**
* A [Host] that is simulates virtual machines on a physical machine using [SimHypervisor].
*/
public class SimHost(
- public val node: Node,
- private val coroutineScope: CoroutineScope,
- hypervisor: SimHypervisorProvider
-) : Host, SimWorkload {
+ override val uid: UUID,
+ override val name: String,
+ model: SimMachineModel,
+ override val meta: Map<String, Any>,
+ context: CoroutineContext,
+ clock: Clock,
+ hypervisor: SimHypervisorProvider,
+ cpuPowerModel: CpuPowerModel = ConstantPowerModel(0.0),
+) : Host, FailureDomain, Powerable, AutoCloseable {
/**
- * The logger instance of this server.
+ * The [CoroutineScope] of the host bounded by the lifecycle of the host.
*/
- private val logger = KotlinLogging.logger {}
+ override val scope: CoroutineScope = CoroutineScope(context)
/**
- * The execution context in which the [Host] runs.
+ * The logger instance of this server.
*/
- private lateinit var ctx: SimExecutionContext
+ private val logger = KotlinLogging.logger {}
override val events: Flow<HostEvent>
get() = _events
@@ -70,12 +79,17 @@ public class SimHost(
/**
* Current total memory use of the images on this hypervisor.
*/
- private var availableMemory: Long = 0
+ private var availableMemory: Long = model.memory.map { it.size }.sum()
+
+ /**
+ * The machine to run on.
+ */
+ public val machine: SimBareMetalMachine = SimBareMetalMachine(scope, clock, model)
/**
* The hypervisor to run multiple workloads.
*/
- private val hypervisor = hypervisor.create(
+ public val hypervisor: SimHypervisor = hypervisor.create(
object : SimHypervisor.Listener {
override fun onSliceFinish(
hypervisor: SimHypervisor,
@@ -107,26 +121,38 @@ public class SimHost(
*/
private val guests = HashMap<Server, Guest>()
- override val uid: UUID
- get() = node.uid
-
- override val name: String
- get() = node.name
-
- override val model: HostModel
- get() = HostModel(node.flavor.cpuCount, node.flavor.memorySize)
-
override val state: HostState
get() = _state
- private var _state: HostState = HostState.UP
+ private var _state: HostState = HostState.DOWN
set(value) {
listeners.forEach { it.onStateChanged(this, value) }
field = value
}
+ override val model: HostModel = HostModel(model.cpus.size, model.memory.map { it.size }.sum())
+
+ override val powerDraw: Flow<Double> = cpuPowerModel.getPowerDraw(this)
+
+ init {
+ // Launch hypervisor onto machine
+ scope.launch {
+ try {
+ _state = HostState.UP
+ machine.run(this@SimHost.hypervisor, emptyMap())
+ } catch (_: CancellationException) {
+ // Ignored
+ } catch (cause: Throwable) {
+ logger.error(cause) { "Host failed" }
+ throw cause
+ } finally {
+ _state = HostState.DOWN
+ }
+ }
+ }
+
override fun canFit(server: Server): Boolean {
val sufficientMemory = availableMemory > server.flavor.memorySize
- val enoughCpus = ctx.machine.cpus.size >= server.flavor.cpuCount
+ val enoughCpus = machine.model.cpus.size >= server.flavor.cpuCount
val canFit = hypervisor.canFit(server.flavor.toMachineModel())
return sufficientMemory && enoughCpus && canFit
@@ -176,11 +202,16 @@ public class SimHost(
listeners.remove(listener)
}
+ override fun close() {
+ scope.cancel()
+ _state = HostState.DOWN
+ }
+
/**
* Convert flavor to machine model.
*/
private fun Flavor.toMachineModel(): SimMachineModel {
- val originalCpu = ctx.machine.cpus[0]
+ val originalCpu = machine.model.cpus[0]
val processingNode = originalCpu.node.copy(coreCount = cpuCount)
val processingUnits = (0 until cpuCount).map { originalCpu.copy(id = it, node = processingNode) }
val memoryUnits = listOf(MemoryUnit("Generic", "Generic", 3200.0, memorySize))
@@ -210,6 +241,14 @@ public class SimHost(
_events.emit(HostEvent.VmsUpdated(this@SimHost, guests.count { it.value.state == ServerState.ACTIVE }, availableMemory))
}
+ override suspend fun fail() {
+ _state = HostState.DOWN
+ }
+
+ override suspend fun recover() {
+ _state = HostState.UP
+ }
+
/**
* A virtual machine instance that the driver manages.
*/
@@ -251,7 +290,7 @@ public class SimHost(
assert(job == null) { "Concurrent job running" }
val workload = server.image.tags["workload"] as SimWorkload
- val job = coroutineScope.launch {
+ val job = scope.launch {
delay(1) // TODO Introduce boot time
init()
cont.resume(Unit)
@@ -286,18 +325,4 @@ public class SimHost(
onGuestStop(this)
}
}
-
- override fun onStart(ctx: SimExecutionContext) {
- this.ctx = ctx
- this.availableMemory = ctx.machine.memory.map { it.size }.sum()
- this.hypervisor.onStart(ctx)
- }
-
- override fun onStart(ctx: SimExecutionContext, cpu: Int): SimResourceCommand {
- return hypervisor.onStart(ctx, cpu)
- }
-
- override fun onNext(ctx: SimExecutionContext, cpu: Int, remainingWork: Double): SimResourceCommand {
- return hypervisor.onNext(ctx, cpu, remainingWork)
- }
}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHostProvisioner.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHostProvisioner.kt
deleted file mode 100644
index bb03777b..00000000
--- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHostProvisioner.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.compute.simulator
-
-import kotlinx.coroutines.*
-import org.opendc.compute.api.Image
-import org.opendc.compute.service.driver.Host
-import org.opendc.metal.Node
-import org.opendc.metal.service.ProvisioningService
-import org.opendc.simulator.compute.SimHypervisorProvider
-import kotlin.coroutines.CoroutineContext
-
-/**
- * A helper class to provision [SimHost]s on top of bare-metal machines using the [ProvisioningService].
- *
- * @param context The [CoroutineContext] to use.
- * @param metal The [ProvisioningService] to use.
- * @param hypervisor The type of hypervisor to use.
- */
-public class SimHostProvisioner(
- private val context: CoroutineContext,
- private val metal: ProvisioningService,
- private val hypervisor: SimHypervisorProvider
-) : AutoCloseable {
- /**
- * The [CoroutineScope] of the service bounded by the lifecycle of the service.
- */
- private val scope = CoroutineScope(context)
-
- /**
- * Provision all machines with a host.
- */
- public suspend fun provisionAll(): List<Host> = coroutineScope {
- metal.nodes().map { node -> async { provision(node) } }.awaitAll()
- }
-
- /**
- * Provision the specified [Node].
- */
- public suspend fun provision(node: Node): Host = coroutineScope {
- val host = SimHost(node, scope, hypervisor)
- metal.deploy(node, Image(node.uid, node.name, mapOf("workload" to host)))
- host
- }
-
- override fun close() {
- scope.cancel()
- }
-}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt
index 0141bc8c..604b69c0 100644
--- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt
@@ -2,7 +2,7 @@ package org.opendc.compute.simulator.power.api
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
-import org.opendc.metal.driver.BareMetalDriver
+import org.opendc.compute.simulator.SimHost
public interface CpuPowerModel {
/**
@@ -18,14 +18,14 @@ public interface CpuPowerModel {
/**
* Emits the values of power consumption for servers.
*
- * @param driver A [BareMetalDriver] that offers host CPU utilization.
+ * @param host A [SimHost] that offers host CPU utilization.
* @param withoutIdle A [Boolean] flag indicates whether (false) add a constant
* power consumption value when the server is idle or (true) not
* with a default value being false.
* @return A [Flow] of values representing the server power draw.
*/
- public fun getPowerDraw(driver: BareMetalDriver, withoutIdle: Boolean = false): Flow<Double> =
- driver.usage.map {
+ public fun getPowerDraw(host: SimHost, withoutIdle: Boolean = false): Flow<Double> =
+ host.machine.usage.map {
computeCpuPower(it)
}
}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt
deleted file mode 100644
index 0d90376e..00000000
--- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.compute.simulator
-
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestCoroutineScope
-import kotlinx.coroutines.withContext
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertAll
-import org.opendc.compute.api.Image
-import org.opendc.metal.NodeEvent
-import org.opendc.metal.NodeState
-import org.opendc.simulator.compute.SimMachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.model.ProcessingNode
-import org.opendc.simulator.compute.model.ProcessingUnit
-import org.opendc.simulator.compute.workload.SimFlopsWorkload
-import org.opendc.simulator.utils.DelayControllerClockAdapter
-import java.util.UUID
-
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimBareMetalDriverTest {
- private lateinit var machineModel: SimMachineModel
-
- @BeforeEach
- fun setUp() {
- val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4)
-
- machineModel = SimMachineModel(
- cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 2000.0) },
- memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
- )
- }
-
- @Test
- fun testFlopsWorkload() {
- val testScope = TestCoroutineScope()
- val clock = DelayControllerClockAdapter(testScope)
-
- var finalState: NodeState = NodeState.UNKNOWN
- var finalTime = 0L
-
- testScope.launch {
- val driver = SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel)
- val image = Image(UUID.randomUUID(), "<unnamed>", mapOf("workload" to SimFlopsWorkload(4_000, utilization = 1.0)))
- // Batch driver commands
- withContext(coroutineContext) {
- driver.init()
- driver.setImage(image)
- val node = driver.start()
- node.events.collect { event ->
- when (event) {
- is NodeEvent.StateChanged -> {
- finalState = event.node.state
- finalTime = clock.millis()
- }
- }
- }
- }
- }
-
- testScope.advanceUntilIdle()
- assertAll(
- { assertEquals(NodeState.SHUTOFF, finalState) },
- { assertEquals(501, finalTime) }
- )
- }
-}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt
index 61bff39f..e48fd947 100644
--- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt
@@ -24,7 +24,6 @@ package org.opendc.compute.simulator
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@@ -39,8 +38,6 @@ import org.opendc.compute.api.Server
import org.opendc.compute.api.ServerState
import org.opendc.compute.api.ServerWatcher
import org.opendc.compute.service.driver.HostEvent
-import org.opendc.metal.Node
-import org.opendc.metal.NodeState
import org.opendc.simulator.compute.SimFairShareHypervisorProvider
import org.opendc.simulator.compute.SimMachineModel
import org.opendc.simulator.compute.model.MemoryUnit
@@ -82,14 +79,8 @@ internal class SimHostTest {
var grantedWork = 0L
var overcommittedWork = 0L
- val node = Node(
- UUID.randomUUID(), "name", emptyMap(), NodeState.SHUTOFF,
- Flavor(machineModel.cpus.size, machineModel.memory.map { it.size }.sum()), Image.EMPTY, emptyFlow()
- )
-
scope.launch {
- val virtDriver = SimHost(node, this, SimFairShareHypervisorProvider())
- val vmm = Image(UUID.randomUUID(), "vmm", mapOf("workload" to virtDriver))
+ val virtDriver = SimHost(UUID.randomUUID(), "test", machineModel, emptyMap(), coroutineContext, clock, SimFairShareHypervisorProvider())
val duration = 5 * 60L
val vmImageA = Image(
UUID.randomUUID(),
@@ -120,13 +111,6 @@ internal class SimHostTest {
)
)
- val metalDriver =
- SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel)
-
- metalDriver.init()
- metalDriver.setImage(vmm)
- metalDriver.start()
-
delay(5)
val flavor = Flavor(2, 0)
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt
deleted file mode 100644
index 33b3db94..00000000
--- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.compute.simulator
-
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestCoroutineScope
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.opendc.compute.api.Image
-import org.opendc.metal.service.SimpleProvisioningService
-import org.opendc.simulator.compute.SimMachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.model.ProcessingNode
-import org.opendc.simulator.compute.model.ProcessingUnit
-import org.opendc.simulator.compute.workload.SimFlopsWorkload
-import org.opendc.simulator.utils.DelayControllerClockAdapter
-import java.util.UUID
-
-/**
- * Test suite for the [SimpleProvisioningService].
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimProvisioningServiceTest {
- private lateinit var machineModel: SimMachineModel
-
- @BeforeEach
- fun setUp() {
- val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4)
-
- machineModel = SimMachineModel(
- cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 2000.0) },
- memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
- )
- }
-
- /**
- * A basic smoke test.
- */
- @Test
- fun testSmoke() {
- val testScope = TestCoroutineScope()
- val clock = DelayControllerClockAdapter(testScope)
-
- testScope.launch {
- val image = Image(UUID.randomUUID(), "<unnamed>", mapOf("machine" to SimFlopsWorkload(1000)))
- val driver = SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel)
-
- val provisioner = SimpleProvisioningService()
- provisioner.create(driver)
- delay(5)
- val nodes = provisioner.nodes()
- val node = provisioner.deploy(nodes.first(), image)
- node.events.collect { println(it) }
- }
-
- testScope.advanceUntilIdle()
- }
-}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/power/CpuPowerModelTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/power/CpuPowerModelTest.kt
index d4d88fb1..9d034a5d 100644
--- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/power/CpuPowerModelTest.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/power/CpuPowerModelTest.kt
@@ -1,18 +1,21 @@
package org.opendc.compute.simulator.power
import io.mockk.*
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runBlockingTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
+import org.opendc.compute.simulator.SimHost
import org.opendc.compute.simulator.power.api.CpuPowerModel
import org.opendc.compute.simulator.power.models.*
-import org.opendc.metal.driver.BareMetalDriver
+import org.opendc.simulator.compute.SimBareMetalMachine
import java.util.stream.Stream
import kotlin.math.pow
+@OptIn(ExperimentalCoroutinesApi::class)
internal class CpuPowerModelTest {
private val epsilon = 10.0.pow(-3)
private val cpuUtil = .9
@@ -44,21 +47,24 @@ internal class CpuPowerModelTest {
powerModel: CpuPowerModel,
expectedPowerConsumption: Double
) {
- val cpuLoads = flowOf(cpuUtil, cpuUtil, cpuUtil)
- val bareMetalDriver = mockkClass(BareMetalDriver::class)
- every { bareMetalDriver.usage } returns cpuLoads
+ runBlockingTest {
+ val cpuLoads = flowOf(cpuUtil, cpuUtil, cpuUtil).stateIn(this)
+ val bareMetalDriver = mockkClass(SimHost::class)
+ val machine = mockkClass(SimBareMetalMachine::class)
+ every { bareMetalDriver.machine } returns machine
+ every { machine.usage } returns cpuLoads
- runBlocking {
val serverPowerDraw = powerModel.getPowerDraw(bareMetalDriver)
- assertEquals(serverPowerDraw.count(), cpuLoads.count())
assertEquals(
serverPowerDraw.first().toDouble(),
flowOf(expectedPowerConsumption).first().toDouble(),
epsilon
)
+
+ verify(exactly = 1) { bareMetalDriver.machine }
+ verify(exactly = 1) { machine.usage }
}
- verify(exactly = 1) { bareMetalDriver.usage }
}
@Suppress("unused")