From e97774dbf274fcb57b9d173f9d674a2ef1b982af Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Mon, 8 Mar 2021 22:19:37 +0100 Subject: compute: Remove use of bare-metal provisioning from compute module This change removes the usage of bare-metal provisioning from the OpenDC Compute module. This significantly simplifies the experiment setup. --- .../org/opendc/compute/service/driver/Host.kt | 5 + .../opendc-compute-simulator/build.gradle.kts | 1 - .../opendc/compute/simulator/SimBareMetalDriver.kt | 188 --------------------- .../kotlin/org/opendc/compute/simulator/SimHost.kt | 103 ++++++----- .../opendc/compute/simulator/SimHostProvisioner.kt | 69 -------- .../compute/simulator/power/api/CpuPowerModel.kt | 8 +- .../compute/simulator/SimBareMetalDriverTest.kt | 92 ---------- .../org/opendc/compute/simulator/SimHostTest.kt | 18 +- .../simulator/SimProvisioningServiceTest.kt | 81 --------- .../compute/simulator/power/CpuPowerModelTest.kt | 22 ++- 10 files changed, 88 insertions(+), 499 deletions(-) delete mode 100644 simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt delete mode 100644 simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHostProvisioner.kt delete mode 100644 simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt delete mode 100644 simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt (limited to 'simulator/opendc-compute') 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 @@ -50,6 +50,11 @@ public interface Host { */ public val state: HostState + /** + * Meta-data associated with the host. + */ + public val meta: Map + /** * The events emitted by the driver. */ 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, - 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() - - /** - * 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 = nodeState - - override val usage: Flow - get() = this.machine.usage - - override val powerDraw: Flow = 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, + 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 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() - 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 = 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 = 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 = - driver.usage.map { + public fun getPowerDraw(host: SimHost, withoutIdle: Boolean = false): Flow = + 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(), "", 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(), "", 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") -- cgit v1.2.3