summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt29
-rw-r--r--simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt11
-rw-r--r--simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt62
-rw-r--r--simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt52
-rw-r--r--simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt64
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt20
-rw-r--r--simulator/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/ExperimentHelpers.kt3
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt7
8 files changed, 238 insertions, 10 deletions
diff --git a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt
index b4fc03f7..baa1ba2f 100644
--- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt
+++ b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt
@@ -29,6 +29,35 @@ import java.util.UUID
*/
public interface ComputeClient : AutoCloseable {
/**
+ * Obtain the list of [Flavor]s accessible by the requesting user.
+ */
+ public suspend fun queryFlavors(): List<Flavor>
+
+ /**
+ * Obtain a [Flavor] by its unique identifier.
+ *
+ * @param id The identifier of the flavor.
+ */
+ public suspend fun findFlavor(id: UUID): Flavor?
+
+ /**
+ * Create a new [Flavor] instance at this compute service.
+ *
+ * @param name The name of the flavor.
+ * @param cpuCount The amount of CPU cores for this flavor.
+ * @param memorySize The size of the memory.
+ * @param labels The identifying labels of the image.
+ * @param meta The non-identifying meta-data of the image.
+ */
+ public suspend fun newFlavor(
+ name: String,
+ cpuCount: Int,
+ memorySize: Long,
+ labels: Map<String, String> = emptyMap(),
+ meta: Map<String, Any> = emptyMap()
+ ): Flavor
+
+ /**
* Obtain the list of [Image]s accessible by the requesting user.
*/
public suspend fun queryImages(): List<Image>
diff --git a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt
index bf5f0ce4..5f511f91 100644
--- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt
+++ b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt
@@ -26,14 +26,19 @@ package org.opendc.compute.api
* Flavors define the compute and memory capacity of [Server] instance. To put it simply, a flavor is an available
* hardware configuration for a server. It defines the size of a virtual server that can be launched.
*/
-public data class Flavor(
+public interface Flavor : Resource {
/**
* The number of (virtual) processing cores to use.
*/
- public val cpuCount: Int,
+ public val cpuCount: Int
/**
* The amount of RAM available to the server (in MB).
*/
public val memorySize: Long
-)
+
+ /**
+ * Delete the flavor instance.
+ */
+ public suspend fun delete()
+}
diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt
new file mode 100644
index 00000000..29f10e27
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.service.internal
+
+import org.opendc.compute.api.Flavor
+import java.util.UUID
+
+/**
+ * A [Flavor] implementation that is passed to clients but delegates its implementation to another class.
+ */
+internal class ClientFlavor(private val delegate: Flavor) : Flavor {
+ override val uid: UUID = delegate.uid
+
+ override var name: String = delegate.name
+ private set
+
+ override var cpuCount: Int = delegate.cpuCount
+ private set
+
+ override var memorySize: Long = delegate.memorySize
+ private set
+
+ override var labels: Map<String, String> = delegate.labels.toMap()
+ private set
+
+ override var meta: Map<String, Any> = delegate.meta.toMap()
+ private set
+
+ override suspend fun delete() {
+ delegate.delete()
+ }
+
+ override suspend fun refresh() {
+ delegate.refresh()
+
+ name = delegate.name
+ cpuCount = delegate.cpuCount
+ memorySize = delegate.memorySize
+ labels = delegate.labels
+ meta = delegate.meta
+ }
+}
diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt
index 3b694537..2c38f7cb 100644
--- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt
+++ b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt
@@ -90,6 +90,11 @@ public class ComputeServiceImpl(
private val activeServers: MutableMap<Server, Host> = mutableMapOf()
/**
+ * The registered flavors for this compute service.
+ */
+ internal val flavors = mutableMapOf<UUID, InternalFlavor>()
+
+ /**
* The registered images for this compute service.
*/
internal val images = mutableMapOf<UUID, InternalImage>()
@@ -131,6 +136,43 @@ public class ComputeServiceImpl(
override fun newClient(): ComputeClient = object : ComputeClient {
private var isClosed: Boolean = false
+ override suspend fun queryFlavors(): List<Flavor> {
+ check(!isClosed) { "Client is already closed" }
+
+ return flavors.values.map { ClientFlavor(it) }
+ }
+
+ override suspend fun findFlavor(id: UUID): Flavor? {
+ check(!isClosed) { "Client is already closed" }
+
+ return flavors[id]?.let { ClientFlavor(it) }
+ }
+
+ override suspend fun newFlavor(
+ name: String,
+ cpuCount: Int,
+ memorySize: Long,
+ labels: Map<String, String>,
+ meta: Map<String, Any>
+ ): Flavor {
+ check(!isClosed) { "Client is already closed" }
+
+ val uid = UUID(clock.millis(), random.nextLong())
+ val flavor = InternalFlavor(
+ this@ComputeServiceImpl,
+ uid,
+ name,
+ cpuCount,
+ memorySize,
+ labels,
+ meta
+ )
+
+ flavors[uid] = flavor
+
+ return ClientFlavor(flavor)
+ }
+
override suspend fun queryImages(): List<Image> {
check(!isClosed) { "Client is already closed" }
@@ -250,12 +292,16 @@ public class ComputeServiceImpl(
requestSchedulingCycle()
}
- internal fun delete(server: InternalServer) {
- checkNotNull(servers.remove(server.uid)) { "Server was not know" }
+ internal fun delete(flavor: InternalFlavor) {
+ checkNotNull(flavors.remove(flavor.uid)) { "Flavor was not known" }
}
internal fun delete(image: InternalImage) {
- checkNotNull(images.remove(image.uid)) { "Server was not know" }
+ checkNotNull(images.remove(image.uid)) { "Image was not known" }
+ }
+
+ internal fun delete(server: InternalServer) {
+ checkNotNull(servers.remove(server.uid)) { "Server was not known" }
}
/**
diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt
new file mode 100644
index 00000000..95e280df
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.service.internal
+
+import org.opendc.compute.api.Flavor
+import java.util.*
+
+/**
+ * Internal stateful representation of a [Flavor].
+ */
+internal class InternalFlavor(
+ private val service: ComputeServiceImpl,
+ override val uid: UUID,
+ name: String,
+ cpuCount: Int,
+ memorySize: Long,
+ labels: Map<String, String>,
+ meta: Map<String, Any>
+) : Flavor {
+ override var name: String = name
+ private set
+
+ override var cpuCount: Int = cpuCount
+ private set
+
+ override var memorySize: Long = memorySize
+ private set
+
+ override val labels: MutableMap<String, String> = labels.toMutableMap()
+
+ override val meta: MutableMap<String, Any> = meta.toMutableMap()
+
+ override suspend fun refresh() {
+ // No-op: this object is the source-of-truth
+ }
+
+ override suspend fun delete() {
+ service.delete(this)
+ }
+
+ override fun equals(other: Any?): Boolean = other is InternalFlavor && uid == other.uid
+
+ override fun hashCode(): Int = uid.hashCode()
+}
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 0672047c..e1a1d87e 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
@@ -115,7 +115,7 @@ internal class SimHostTest {
delay(5)
- val flavor = Flavor(2, 0)
+ val flavor = MockFlavor(2, 0)
virtDriver.events
.onEach { event ->
when (event) {
@@ -143,6 +143,24 @@ internal class SimHostTest {
)
}
+ private class MockFlavor(
+ override val cpuCount: Int,
+ override val memorySize: Long
+ ) : Flavor {
+ override val uid: UUID = UUID.randomUUID()
+ override val name: String = "test"
+ override val labels: Map<String, String> = emptyMap()
+ override val meta: Map<String, Any> = emptyMap()
+
+ override suspend fun delete() {
+ throw NotImplementedError()
+ }
+
+ override suspend fun refresh() {
+ throw NotImplementedError()
+ }
+ }
+
private class MockImage(
override val uid: UUID,
override val name: String,
diff --git a/simulator/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/ExperimentHelpers.kt b/simulator/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/ExperimentHelpers.kt
index c94ee5d4..f327b55d 100644
--- a/simulator/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/ExperimentHelpers.kt
+++ b/simulator/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/ExperimentHelpers.kt
@@ -246,7 +246,8 @@ public suspend fun processTrace(
val server = client.newServer(
entry.name,
image,
- Flavor(
+ client.newFlavor(
+ entry.name,
entry.meta["cores"] as Int,
entry.meta["required-memory"] as Long
),
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt
index 34d19e4f..c5c4bf97 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt
@@ -262,9 +262,9 @@ public class StageWorkflowService(
val instance = taskQueue.peek()
val cores = instance.task.metadata[WORKFLOW_TASK_CORES] as? Int ?: 1
- val flavor = Flavor(cores, 1000) // TODO How to determine memory usage for workflow task
val image = image
coroutineScope.launch {
+ val flavor = computeClient.newFlavor(instance.task.name, cores, 1000) // TODO How to determine memory usage for workflow task
val server = computeClient.newServer(instance.task.name, image, flavor, start = false, meta = instance.task.metadata)
instance.state = TaskStatus.ACTIVE
@@ -299,7 +299,10 @@ public class StageWorkflowService(
ServerState.TERMINATED, ServerState.ERROR -> {
val task = taskByServer.remove(server) ?: throw IllegalStateException()
- coroutineScope.launch { server.delete() }
+ coroutineScope.launch {
+ server.delete()
+ server.flavor.delete()
+ }
val job = task.job
task.state = TaskStatus.FINISHED