diff options
15 files changed, 177 insertions, 194 deletions
diff --git a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt index 577fbc73..c26d0b8b 100644 --- a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt +++ b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt @@ -31,14 +31,14 @@ public interface ComputeClient : AutoCloseable { /** * Obtain the list of [Flavor]s accessible by the requesting user. */ - public suspend fun queryFlavors(): List<Flavor> + public 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? + public fun findFlavor(id: UUID): Flavor? /** * Create a new [Flavor] instance at this compute service. @@ -49,7 +49,7 @@ public interface ComputeClient : AutoCloseable { * @param labels The identifying labels of the image. * @param meta The non-identifying meta-data of the image. */ - public suspend fun newFlavor( + public fun newFlavor( name: String, cpuCount: Int, memorySize: Long, @@ -60,14 +60,14 @@ public interface ComputeClient : AutoCloseable { /** * Obtain the list of [Image]s accessible by the requesting user. */ - public suspend fun queryImages(): List<Image> + public fun queryImages(): List<Image> /** * Obtain a [Image] by its unique identifier. * * @param id The identifier of the image. */ - public suspend fun findImage(id: UUID): Image? + public fun findImage(id: UUID): Image? /** * Create a new [Image] instance at this compute service. @@ -76,7 +76,7 @@ public interface ComputeClient : AutoCloseable { * @param labels The identifying labels of the image. * @param meta The non-identifying meta-data of the image. */ - public suspend fun newImage( + public fun newImage( name: String, labels: Map<String, String> = emptyMap(), meta: Map<String, Any> = emptyMap() @@ -85,14 +85,14 @@ public interface ComputeClient : AutoCloseable { /** * Obtain the list of [Server]s accessible by the requesting user. */ - public suspend fun queryServers(): List<Server> + public fun queryServers(): List<Server> /** * Obtain a [Server] by its unique identifier. * * @param id The identifier of the server. */ - public suspend fun findServer(id: UUID): Server? + public fun findServer(id: UUID): Server? /** * Create a new [Server] instance at this compute service. @@ -104,7 +104,7 @@ public interface ComputeClient : AutoCloseable { * @param meta The non-identifying meta-data of the server. * @param start A flag to indicate that the server should be started immediately. */ - public suspend fun newServer( + public fun newServer( name: String, image: Image, flavor: Flavor, diff --git a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt index 5f511f91..d76e0fba 100644 --- a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt +++ b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt @@ -36,9 +36,4 @@ public interface Flavor : Resource { * 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/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Image.kt b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Image.kt index 83e63b81..c4a04b96 100644 --- a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Image.kt +++ b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Image.kt @@ -25,9 +25,4 @@ package org.opendc.compute.api /** * An image containing a bootable operating system that can directly be executed by physical or virtual server. */ -public interface Image : Resource { - /** - * Delete the image instance. - */ - public suspend fun delete() -} +public interface Image : Resource diff --git a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Resource.kt b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Resource.kt index 08120848..58082130 100644 --- a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Resource.kt +++ b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Resource.kt @@ -49,7 +49,12 @@ public interface Resource { public val meta: Map<String, Any> /** - * Refresh the local state of the resource. + * Reload the attributes of the resource. */ - public suspend fun refresh() + public fun reload() + + /** + * Delete the resource. + */ + public fun delete() } diff --git a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Server.kt b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Server.kt index 64b73d0b..b4cc5129 100644 --- a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Server.kt +++ b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Server.kt @@ -50,27 +50,13 @@ public interface Server : Resource { /** * Request the server to be started. - * - * This method is guaranteed to return after the request was acknowledged, but might return before the server was - * started. */ - public suspend fun start() + public fun start() /** * Request the server to be stopped. - * - * This method is guaranteed to return after the request was acknowledged, but might return before the server was - * stopped. - */ - public suspend fun stop() - - /** - * Request the server to be deleted. - * - * This method is guaranteed to return after the request was acknowledged, but might return before the server was - * deleted. */ - public suspend fun delete() + public fun stop() /** * Register the specified [ServerWatcher] to watch the state of the server. diff --git a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerWatcher.kt b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerWatcher.kt index 48a17b30..cf995fc3 100644 --- a/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerWatcher.kt +++ b/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerWatcher.kt @@ -29,9 +29,6 @@ public interface ServerWatcher { /** * This method is invoked when the state of a [Server] changes. * - * Note that the state of [server] might not reflect the state as reported by the invocation, as a call to - * [Server.refresh] is required to update its state. - * * @param server The server whose state has changed. * @param newState The new state of the server. */ diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt index 4a8d3046..45a3d472 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt @@ -46,12 +46,12 @@ internal class ClientFlavor(private val delegate: Flavor) : Flavor { override var meta: Map<String, Any> = delegate.meta.toMap() private set - override suspend fun delete() { + override fun delete() { delegate.delete() } - override suspend fun refresh() { - delegate.refresh() + override fun reload() { + delegate.reload() name = delegate.name cpuCount = delegate.cpuCount diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt index f0032acf..eb963f0e 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt @@ -40,13 +40,13 @@ internal class ClientImage(private val delegate: Image) : Image { override var meta: Map<String, Any> = delegate.meta.toMap() private set - override suspend fun delete() { + override fun delete() { delegate.delete() - refresh() + reload() } - override suspend fun refresh() { - delegate.refresh() + override fun reload() { + delegate.reload() name = delegate.name labels = delegate.labels diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt index 6cd7d30f..f2248466 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt @@ -59,19 +59,19 @@ internal class ClientServer(private val delegate: Server) : Server, ServerWatche override var launchedAt: Instant? = null private set - override suspend fun start() { + override fun start() { delegate.start() - refresh() + reload() } - override suspend fun stop() { + override fun stop() { delegate.stop() - refresh() + reload() } - override suspend fun delete() { + override fun delete() { delegate.delete() - refresh() + reload() } override fun watch(watcher: ServerWatcher) { @@ -90,8 +90,8 @@ internal class ClientServer(private val delegate: Server) : Server, ServerWatche } } - override suspend fun refresh() { - delegate.refresh() + override fun reload() { + delegate.reload() name = delegate.name flavor = delegate.flavor diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt index 77932545..ffebd5fa 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt @@ -122,118 +122,7 @@ internal class ComputeServiceImpl( override fun newClient(): ComputeClient { check(!isClosed) { "Service is already closed" } - return object : ComputeClient { - private var isClosed: Boolean = false - - override suspend fun queryFlavors(): List<Flavor> { - check(!isClosed) { "Client is already closed" } - - return flavorById.values.map { ClientFlavor(it) } - } - - override suspend fun findFlavor(id: UUID): Flavor? { - check(!isClosed) { "Client is already closed" } - - return flavorById[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 - ) - - flavorById[uid] = flavor - - return ClientFlavor(flavor) - } - - override suspend fun queryImages(): List<Image> { - check(!isClosed) { "Client is already closed" } - - return imageById.values.map { ClientImage(it) } - } - - override suspend fun findImage(id: UUID): Image? { - check(!isClosed) { "Client is already closed" } - - return imageById[id]?.let { ClientImage(it) } - } - - override suspend fun newImage(name: String, labels: Map<String, String>, meta: Map<String, Any>): Image { - check(!isClosed) { "Client is already closed" } - - val uid = UUID(clock.millis(), random.nextLong()) - val image = InternalImage(this@ComputeServiceImpl, uid, name, labels, meta) - - imageById[uid] = image - - return ClientImage(image) - } - - override suspend fun newServer( - name: String, - image: Image, - flavor: Flavor, - labels: Map<String, String>, - meta: Map<String, Any>, - start: Boolean - ): Server { - check(!isClosed) { "Client is closed" } - - val uid = UUID(clock.millis(), random.nextLong()) - val server = InternalServer( - this@ComputeServiceImpl, - uid, - name, - requireNotNull(flavorById[flavor.uid]) { "Unknown flavor" }, - requireNotNull(imageById[image.uid]) { "Unknown image" }, - labels.toMutableMap(), - meta.toMutableMap() - ) - - serverById[uid] = server - servers.add(server) - - if (start) { - server.start() - } - - return ClientServer(server) - } - - override suspend fun findServer(id: UUID): Server? { - check(!isClosed) { "Client is already closed" } - - return serverById[id]?.let { ClientServer(it) } - } - - override suspend fun queryServers(): List<Server> { - check(!isClosed) { "Client is already closed" } - - return serverById.values.map { ClientServer(it) } - } - - override fun close() { - isClosed = true - } - - override fun toString(): String = "ComputeClient" - } + return Client(this) } override fun addHost(host: Host) { @@ -460,4 +349,120 @@ internal class ComputeServiceImpl( requestSchedulingCycle() } } + + /** + * Implementation of [ComputeClient] using a [ComputeService]. + */ + private class Client(private val service: ComputeServiceImpl) : ComputeClient { + private var isClosed: Boolean = false + + override fun queryFlavors(): List<Flavor> { + check(!isClosed) { "Client is already closed" } + + return service.flavorById.values.map { ClientFlavor(it) } + } + + override fun findFlavor(id: UUID): Flavor? { + check(!isClosed) { "Client is already closed" } + + return service.flavorById[id]?.let { ClientFlavor(it) } + } + + override 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(service.clock.millis(), service.random.nextLong()) + val flavor = InternalFlavor( + service, + uid, + name, + cpuCount, + memorySize, + labels, + meta + ) + + service.flavorById[uid] = flavor + + return ClientFlavor(flavor) + } + + override fun queryImages(): List<Image> { + check(!isClosed) { "Client is already closed" } + + return service.imageById.values.map { ClientImage(it) } + } + + override fun findImage(id: UUID): Image? { + check(!isClosed) { "Client is already closed" } + + return service.imageById[id]?.let { ClientImage(it) } + } + + override fun newImage(name: String, labels: Map<String, String>, meta: Map<String, Any>): Image { + check(!isClosed) { "Client is already closed" } + + val uid = UUID(service.clock.millis(), service.random.nextLong()) + val image = InternalImage(service, uid, name, labels, meta) + + service.imageById[uid] = image + + return ClientImage(image) + } + + override fun newServer( + name: String, + image: Image, + flavor: Flavor, + labels: Map<String, String>, + meta: Map<String, Any>, + start: Boolean + ): Server { + check(!isClosed) { "Client is closed" } + + val uid = UUID(service.clock.millis(), service.random.nextLong()) + val server = InternalServer( + service, + uid, + name, + requireNotNull(service.flavorById[flavor.uid]) { "Unknown flavor" }, + requireNotNull(service.imageById[image.uid]) { "Unknown image" }, + labels.toMutableMap(), + meta.toMutableMap() + ) + + service.serverById[uid] = server + service.servers.add(server) + + if (start) { + server.start() + } + + return ClientServer(server) + } + + override fun findServer(id: UUID): Server? { + check(!isClosed) { "Client is already closed" } + + return service.serverById[id]?.let { ClientServer(it) } + } + + override fun queryServers(): List<Server> { + check(!isClosed) { "Client is already closed" } + + return service.serverById.values.map { ClientServer(it) } + } + + override fun close() { + isClosed = true + } + + override fun toString(): String = "ComputeService.Client" + } } diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt index acd87dfc..077ec865 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt @@ -50,11 +50,11 @@ internal class InternalFlavor( override val meta: MutableMap<String, Any> = meta.toMutableMap() - override suspend fun refresh() { + override fun reload() { // No-op: this object is the source-of-truth } - override suspend fun delete() { + override fun delete() { service.delete(this) } diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt index a0a35a55..b27ef33a 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt @@ -40,11 +40,11 @@ internal class InternalImage( override val meta: MutableMap<String, Any> = meta.toMutableMap() - override suspend fun refresh() { + override fun reload() { // No-op: this object is the source-of-truth } - override suspend fun delete() { + override fun delete() { service.delete(this) } diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt index e3bae405..c1353ba1 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt @@ -67,7 +67,7 @@ internal class InternalServer( */ private var request: ComputeServiceImpl.SchedulingRequest? = null - override suspend fun start() { + override fun start() { when (state) { ServerState.RUNNING -> { logger.debug { "User tried to start server but server is already running" } @@ -90,7 +90,7 @@ internal class InternalServer( } } - override suspend fun stop() { + override fun stop() { when (state) { ServerState.PROVISIONING -> { cancelProvisioningRequest() @@ -104,7 +104,7 @@ internal class InternalServer( } } - override suspend fun delete() { + override fun delete() { when (state) { ServerState.PROVISIONING, ServerState.TERMINATED -> { cancelProvisioningRequest() @@ -129,7 +129,7 @@ internal class InternalServer( watchers -= watcher } - override suspend fun refresh() { + override fun reload() { // No-op: this object is the source-of-truth } diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt index b5685aba..13b926e8 100644 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt +++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt @@ -170,7 +170,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -183,7 +183,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -196,7 +196,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -210,7 +210,7 @@ internal class ComputeServiceTest { server.start() server.stop() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -231,7 +231,7 @@ internal class ComputeServiceTest { server.start() delay(10L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) verify { host.canFit(server) } @@ -262,7 +262,7 @@ internal class ComputeServiceTest { listeners.forEach { it.onStateChanged(host, HostState.UP) } delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) verify { host.canFit(server) } @@ -293,7 +293,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) verify(exactly = 0) { host.canFit(server) } @@ -351,7 +351,7 @@ internal class ComputeServiceTest { listeners.forEach { it.onStateChanged(host, slot.captured, ServerState.RUNNING) } - server.refresh() + server.reload() assertEquals(ServerState.RUNNING, server.state) verify { watcher.onStateChanged(server, ServerState.RUNNING) } @@ -359,7 +359,7 @@ internal class ComputeServiceTest { // Stop server listeners.forEach { it.onStateChanged(host, slot.captured, ServerState.TERMINATED) } - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) verify { watcher.onStateChanged(server, ServerState.TERMINATED) } @@ -387,7 +387,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) } } diff --git a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt index a496cc99..1734daf5 100644 --- a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt +++ b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt @@ -305,11 +305,11 @@ internal class SimHostTest { override val labels: Map<String, String> = emptyMap() override val meta: Map<String, Any> = emptyMap() - override suspend fun delete() { + override fun delete() { throw NotImplementedError() } - override suspend fun refresh() { + override fun reload() { throw NotImplementedError() } } @@ -320,11 +320,11 @@ internal class SimHostTest { override val labels: Map<String, String>, override val meta: Map<String, Any> ) : Image { - override suspend fun delete() { + override fun delete() { throw NotImplementedError() } - override suspend fun refresh() { + override fun reload() { throw NotImplementedError() } } @@ -343,16 +343,16 @@ internal class SimHostTest { override val launchedAt: Instant? = null - override suspend fun start() {} + override fun start() {} - override suspend fun stop() {} + override fun stop() {} - override suspend fun delete() {} + override fun delete() {} override fun watch(watcher: ServerWatcher) {} override fun unwatch(watcher: ServerWatcher) {} - override suspend fun refresh() {} + override fun reload() {} } } |
