diff options
Diffstat (limited to 'simulator/opendc-compute/src/main')
8 files changed, 283 insertions, 8 deletions
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerContext.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerContext.kt index 9674c98d..82cec00a 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerContext.kt +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerContext.kt @@ -66,7 +66,7 @@ public interface ServerContext { * @param triggerMode The trigger condition to resume execution. */ public suspend fun run(slice: Slice, triggerMode: TriggerMode = TriggerMode.FIRST): Unit = - select<Unit> { onRun(slice, triggerMode).invoke {} } + select { onRun(slice, triggerMode).invoke {} } /** * Ask the processors cores to run the specified [batch] of work slices and suspend execution until the trigger @@ -88,7 +88,7 @@ public interface ServerContext { batch: Sequence<Slice>, triggerMode: TriggerMode = TriggerMode.FIRST, merge: (Slice, Slice) -> Slice = { _, r -> r } - ): Unit = select<Unit> { onRun(batch, triggerMode, merge).invoke {} } + ): Unit = select { onRun(batch, triggerMode, merge).invoke {} } /** * Ask the processor cores to run the specified [slice] and select when the trigger condition is met as specified diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/SimWorkloadImage.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/SimWorkloadImage.kt new file mode 100644 index 00000000..7caedf6d --- /dev/null +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/SimWorkloadImage.kt @@ -0,0 +1,45 @@ +/* + * 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.core.image + +import org.opendc.compute.core.execution.ServerContext +import org.opendc.core.resource.TagContainer +import org.opendc.simulator.compute.workload.SimWorkload +import java.util.* + +/** + * An application [Image] that runs a [SimWorkload]. + * + * @property uid The unique identifier of this image. + * @property name The name of this image. + * @property tags The tags attached to the image. + * @property workload The workload to run for this image. + */ +public data class SimWorkloadImage( + public override val uid: UUID, + public override val name: String, + public override val tags: TagContainer, + public val workload: SimWorkload +) : Image { + override suspend fun invoke(ctx: ServerContext): Unit = TODO() +} diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimBareMetalDriver.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimBareMetalDriver.kt new file mode 100644 index 00000000..e9346a6c --- /dev/null +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimBareMetalDriver.kt @@ -0,0 +1,229 @@ +/* + * 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.metal.driver + +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.Flow +import org.opendc.compute.core.Flavor +import org.opendc.compute.core.Server +import org.opendc.compute.core.ServerEvent +import org.opendc.compute.core.ServerState +import org.opendc.compute.core.execution.ShutdownException +import org.opendc.compute.core.image.EmptyImage +import org.opendc.compute.core.image.Image +import org.opendc.compute.core.image.SimWorkloadImage +import org.opendc.compute.metal.Node +import org.opendc.compute.metal.NodeEvent +import org.opendc.compute.metal.NodeState +import org.opendc.compute.metal.power.ConstantPowerModel +import org.opendc.core.power.PowerModel +import org.opendc.core.services.ServiceRegistry +import org.opendc.simulator.compute.SimMachine +import org.opendc.simulator.compute.SimMachineModel +import org.opendc.utils.flow.EventFlow +import org.opendc.utils.flow.StateFlow +import java.time.Clock +import java.util.UUID +import kotlin.random.Random + +/** + * 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 powerModel The 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, + powerModel: PowerModel<SimBareMetalDriver> = ConstantPowerModel(0.0) +) : BareMetalDriver { + /** + * 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, EmptyImage, null, events)) + + override val node: Flow<Node> = nodeState + + override val usage: Flow<Double> + get() = this.machine.usage + + override val powerDraw: Flow<Double> = powerModel(this) + + /** + * The internal random instance. + */ + private val random = Random(uid.leastSignificantBits xor uid.mostSignificantBits) + + /** + * The [SimMachine] we use to run the workload. + */ + private val machine = SimMachine(coroutineScope, clock, machine) + + /** + * The [Job] that runs the simulated workload. + */ + private var job: Job? = null + + /** + * The event stream to publish to for the server. + */ + private var serverEvents: EventFlow<ServerEvent>? = 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 events = EventFlow<ServerEvent>() + serverEvents = events + val server = Server( + UUID(random.nextLong(), random.nextLong()), + node.name, + emptyMap(), + flavor, + node.image, + ServerState.BUILD, + ServiceRegistry().put(BareMetalDriver, this@SimBareMetalDriver), + events + ) + + job = coroutineScope.launch { + delay(1) // TODO Introduce boot time + initMachine() + try { + machine.run((node.image as SimWorkloadImage).workload) + exitMachine(null) + } catch (_: CancellationException) { + // Ignored + } catch (cause: Throwable) { + exitMachine(cause) + } + } + + setNode(node.copy(state = NodeState.BOOT, server = server)) + return nodeState.value + } + + private fun initMachine() { + val server = nodeState.value.server?.copy(state = ServerState.ACTIVE) + setNode(nodeState.value.copy(state = NodeState.ACTIVE, server = server)) + } + + private fun exitMachine(cause: Throwable?) { + val newServerState = + if (cause == null || (cause is ShutdownException && cause.cause == null)) + ServerState.SHUTOFF + else + ServerState.ERROR + val newNodeState = + if (cause == null || (cause is ShutdownException && cause.cause != null)) + nodeState.value.state + else + NodeState.ERROR + val server = nodeState.value.server?.copy(state = newServerState) + setNode(nodeState.value.copy(state = newNodeState, server = server)) + + serverEvents?.close() + serverEvents = null + } + + override suspend fun stop(): Node { + val node = nodeState.value + if (node.state == NodeState.SHUTOFF) { + return node + } + + job?.cancelAndJoin() + setNode(node.copy(state = NodeState.SHUTOFF, server = null)) + 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)) + } + + if (field.server != null && value.server != null && field.server.state != value.server.state) { + serverEvents?.emit(ServerEvent.StateChanged(value.server, field.server.state)) + } + + nodeState.value = value + } + + override val scope: CoroutineScope + get() = coroutineScope + + override suspend fun fail() { + val server = nodeState.value.server?.copy(state = ServerState.ERROR) + setNode(nodeState.value.copy(state = NodeState.ERROR, server = server)) + } + + override suspend fun recover() { + val server = nodeState.value.server?.copy(state = ServerState.ACTIVE) + setNode(nodeState.value.copy(state = NodeState.ACTIVE, server = server)) + } + + override fun toString(): String = "SimBareMetalDriver(node = ${nodeState.value.uid})" +} diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt index 817528f6..c4897197 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt @@ -92,7 +92,8 @@ public class SimpleBareMetalDriver( /** * The flavor that corresponds to this machine. */ - private val flavor = Flavor(cpus.size, memoryUnits.map { it.size }.sum()) + private val flavor = + Flavor(cpus.size, memoryUnits.map { it.size }.sum()) /** * The current active server context. diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimpleVirtDriver.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimpleVirtDriver.kt index fb3d5f84..d581e651 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimpleVirtDriver.kt +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimpleVirtDriver.kt @@ -105,7 +105,7 @@ public class SimpleVirtDriver( override suspend fun spawn( name: String, image: Image, - flavor: Flavor + flavor: org.opendc.compute.core.Flavor ): Server { val requiredMemory = flavor.memorySize if (availableMemory - requiredMemory < 0) { diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/VirtDriver.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/VirtDriver.kt index 9663f4da..54728eb6 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/VirtDriver.kt +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/VirtDriver.kt @@ -51,7 +51,7 @@ public interface VirtDriver { public suspend fun spawn( name: String, image: Image, - flavor: Flavor + flavor: org.opendc.compute.core.Flavor ): Server public companion object Key : AbstractServiceKey<VirtDriver>(UUID.randomUUID(), "virtual-driver") diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/SimpleVirtProvisioningService.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/SimpleVirtProvisioningService.kt index 3141529f..f021d3f0 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/SimpleVirtProvisioningService.kt +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/SimpleVirtProvisioningService.kt @@ -119,7 +119,7 @@ public class SimpleVirtProvisioningService( override suspend fun deploy( name: String, image: Image, - flavor: Flavor + flavor: org.opendc.compute.core.Flavor ): Server { eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( @@ -373,7 +373,7 @@ public class SimpleVirtProvisioningService( public data class ImageView( public val name: String, public val image: Image, - public val flavor: Flavor, + public val flavor: org.opendc.compute.core.Flavor, public val continuation: Continuation<Server>, public var server: Server? = null ) diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningService.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningService.kt index 7ed577c4..13dfd640 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningService.kt +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningService.kt @@ -58,7 +58,7 @@ public interface VirtProvisioningService { public suspend fun deploy( name: String, image: Image, - flavor: Flavor + flavor: org.opendc.compute.core.Flavor ): Server /** |
