diff options
Diffstat (limited to 'simulator/opendc-compute')
47 files changed, 0 insertions, 4104 deletions
diff --git a/simulator/opendc-compute/build.gradle.kts b/simulator/opendc-compute/build.gradle.kts deleted file mode 100644 index bf920306..00000000 --- a/simulator/opendc-compute/build.gradle.kts +++ /dev/null @@ -1,23 +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. - */ - -description = "Cloud computing fabric controller of OpenDC" diff --git a/simulator/opendc-compute/opendc-compute-api/build.gradle.kts b/simulator/opendc-compute/opendc-compute-api/build.gradle.kts deleted file mode 100644 index 835dbbb8..00000000 --- a/simulator/opendc-compute/opendc-compute-api/build.gradle.kts +++ /dev/null @@ -1,32 +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. - */ - -description = "API interface for the OpenDC Compute service" - -/* Build configuration */ -plugins { - `kotlin-library-conventions` -} - -dependencies { - api(platform(project(":opendc-platform"))) -} 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 deleted file mode 100644 index baa1ba2f..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ComputeClient.kt +++ /dev/null @@ -1,120 +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.api - -import java.util.UUID - -/** - * A client interface for the OpenDC Compute service. - */ -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> - - /** - * Obtain a [Image] by its unique identifier. - * - * @param id The identifier of the image. - */ - public suspend fun findImage(id: UUID): Image? - - /** - * Create a new [Image] instance at this compute service. - * - * @param name The name of the image. - * @param labels The identifying labels of the image. - * @param meta The non-identifying meta-data of the image. - */ - public suspend fun newImage( - name: String, - labels: Map<String, String> = emptyMap(), - meta: Map<String, Any> = emptyMap() - ): Image - - /** - * Obtain the list of [Server]s accessible by the requesting user. - */ - public suspend 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? - - /** - * Create a new [Server] instance at this compute service. - * - * @param name The name of the server to deploy. - * @param image The image to be deployed. - * @param flavor The flavor of the machine instance to run this [image] on. - * @param labels The identifying labels of the server. - * @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( - name: String, - image: Image, - flavor: Flavor, - labels: Map<String, String> = emptyMap(), - meta: Map<String, Any> = emptyMap(), - start: Boolean = true - ): Server - - /** - * Release the resources associated with this client, preventing any further API calls. - */ - public override fun close() -} 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 deleted file mode 100644 index 5f511f91..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Flavor.kt +++ /dev/null @@ -1,44 +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.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 interface Flavor : Resource { - /** - * The number of (virtual) processing cores to use. - */ - 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-api/src/main/kotlin/org/opendc/compute/api/Image.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Image.kt deleted file mode 100644 index 83e63b81..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Image.kt +++ /dev/null @@ -1,33 +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.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() -} diff --git a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/InsufficientServerCapacityException.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/InsufficientServerCapacityException.kt deleted file mode 100644 index 8fbb7308..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/InsufficientServerCapacityException.kt +++ /dev/null @@ -1,29 +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.api - -/** - * This exception is thrown to indicate that the compute service does not have enough capacity at the moment to - * fulfill a launch request. - */ -public class InsufficientServerCapacityException(override val cause: Throwable? = null) : Exception("There was insufficient capacity available to satisfy the launch request") diff --git a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Resource.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Resource.kt deleted file mode 100644 index 08120848..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Resource.kt +++ /dev/null @@ -1,55 +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.api - -import java.util.UUID - -/** - * A generic resource provided by the OpenDC Compute service. - */ -public interface Resource { - /** - * The unique identifier of the resource. - */ - public val uid: UUID - - /** - * The name of the resource. - */ - public val name: String - - /** - * The identifying labels attached to the resource. - */ - public val labels: Map<String, String> - - /** - * The non-identifying metadata attached to the resource. - */ - public val meta: Map<String, Any> - - /** - * Refresh the local state of the resource. - */ - public suspend fun refresh() -} diff --git a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Server.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Server.kt deleted file mode 100644 index b508a9f8..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/Server.kt +++ /dev/null @@ -1,81 +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.api - -/** - * A stateful object representing a server instance that is running on some physical or virtual machine. - */ -public interface Server : Resource { - /** - * The flavor of the server. - */ - public val flavor: Flavor - - /** - * The image of the server. - */ - public val image: Image - - /** - * The last known state of the server. - */ - public val state: ServerState - - /** - * 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() - - /** - * 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() - - /** - * Register the specified [ServerWatcher] to watch the state of the server. - * - * @param watcher The watcher to register for the server. - */ - public fun watch(watcher: ServerWatcher) - - /** - * De-register the specified [ServerWatcher] from the server to stop it from receiving events. - * - * @param watcher The watcher to de-register from the server. - */ - public fun unwatch(watcher: ServerWatcher) -} diff --git a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerState.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerState.kt deleted file mode 100644 index a4d7d7d7..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerState.kt +++ /dev/null @@ -1,53 +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.api - -/** - * An enumeration describing the possible states of a server. - */ -public enum class ServerState { - /** - * Resources are being allocated for the instance. The instance is not running yet. - */ - PROVISIONING, - - /** - * A user shut down the instance. - */ - TERMINATED, - - /** - * The server instance is booting up or running. - */ - RUNNING, - - /** - * The server is in an error state. - */ - ERROR, - - /** - * The server has been deleted and cannot be started later on. - */ - DELETED, -} diff --git a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerWatcher.kt b/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerWatcher.kt deleted file mode 100644 index 48a17b30..00000000 --- a/simulator/opendc-compute/opendc-compute-api/src/main/kotlin/org/opendc/compute/api/ServerWatcher.kt +++ /dev/null @@ -1,39 +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.api - -/** - * An interface used to watch the state of [Server] instances. - */ -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. - */ - public fun onStateChanged(server: Server, newState: ServerState) {} -} diff --git a/simulator/opendc-compute/opendc-compute-service/build.gradle.kts b/simulator/opendc-compute/opendc-compute-service/build.gradle.kts deleted file mode 100644 index 909e2dcd..00000000 --- a/simulator/opendc-compute/opendc-compute-service/build.gradle.kts +++ /dev/null @@ -1,41 +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. - */ - -description = "OpenDC Compute Service implementation" - -/* Build configuration */ -plugins { - `kotlin-library-conventions` - `testing-conventions` - `jacoco-conventions` -} - -dependencies { - api(platform(project(":opendc-platform"))) - api(project(":opendc-compute:opendc-compute-api")) - api(project(":opendc-telemetry:opendc-telemetry-api")) - implementation(project(":opendc-utils")) - implementation("io.github.microutils:kotlin-logging") - - testImplementation(project(":opendc-simulator:opendc-simulator-core")) - testRuntimeOnly("org.apache.logging.log4j:log4j-slf4j-impl") -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt deleted file mode 100644 index 1873eb99..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt +++ /dev/null @@ -1,85 +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.service - -import io.opentelemetry.api.metrics.Meter -import org.opendc.compute.api.ComputeClient -import org.opendc.compute.service.driver.Host -import org.opendc.compute.service.internal.ComputeServiceImpl -import org.opendc.compute.service.scheduler.ComputeScheduler -import java.time.Clock -import kotlin.coroutines.CoroutineContext - -/** - * The [ComputeService] hosts the API implementation of the OpenDC Compute service. - */ -public interface ComputeService : AutoCloseable { - /** - * The hosts that are used by the compute service. - */ - public val hosts: Set<Host> - - /** - * The number of hosts available in the system. - */ - public val hostCount: Int - - /** - * Create a new [ComputeClient] to control the compute service. - */ - public fun newClient(): ComputeClient - - /** - * Add a [host] to the scheduling pool of the compute service. - */ - public fun addHost(host: Host) - - /** - * Remove a [host] from the scheduling pool of the compute service. - */ - public fun removeHost(host: Host) - - /** - * Terminate the lifecycle of the compute service, stopping all running instances. - */ - public override fun close() - - public companion object { - /** - * Construct a new [ComputeService] implementation. - * - * @param context The [CoroutineContext] to use in the service. - * @param clock The clock instance to use. - * @param scheduler The scheduler implementation to use. - */ - public operator fun invoke( - context: CoroutineContext, - clock: Clock, - meter: Meter, - scheduler: ComputeScheduler, - schedulingQuantum: Long = 300000, - ): ComputeService { - return ComputeServiceImpl(context, clock, meter, scheduler, schedulingQuantum) - } - } -} 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 deleted file mode 100644 index bed15dfd..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt +++ /dev/null @@ -1,103 +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.service.driver - -import org.opendc.compute.api.Server -import java.util.* - -/** - * Base interface for representing compute resources that host virtualized [Server] instances. - */ -public interface Host { - /** - * A unique identifier representing the host. - */ - public val uid: UUID - - /** - * The name of this host. - */ - public val name: String - - /** - * The machine model of the host. - */ - public val model: HostModel - - /** - * The state of the host. - */ - public val state: HostState - - /** - * Meta-data associated with the host. - */ - public val meta: Map<String, Any> - - /** - * Determine whether the specified [instance][server] can still fit on this host. - */ - public fun canFit(server: Server): Boolean - - /** - * Register the specified [instance][server] on the host. - * - * Once the method returns, the instance should be running if [start] is true or else the instance should be - * stopped. - */ - public suspend fun spawn(server: Server, start: Boolean = true) - - /** - * Determine whether the specified [instance][server] exists on the host. - */ - public operator fun contains(server: Server): Boolean - - /** - * Start the server [instance][server] if it is currently not running on this host. - * - * @throws IllegalArgumentException if the server is not present on the host. - */ - public suspend fun start(server: Server) - - /** - * Stop the server [instance][server] if it is currently running on this host. - * - * @throws IllegalArgumentException if the server is not present on the host. - */ - public suspend fun stop(server: Server) - - /** - * Delete the specified [instance][server] on this host and cleanup all resources associated with it. - */ - public suspend fun delete(server: Server) - - /** - * Add a [HostListener] to this host. - */ - public fun addListener(listener: HostListener) - - /** - * Remove a [HostListener] from this host. - */ - public fun removeListener(listener: HostListener) -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostListener.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostListener.kt deleted file mode 100644 index f076cae3..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostListener.kt +++ /dev/null @@ -1,41 +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.service.driver - -import org.opendc.compute.api.Server -import org.opendc.compute.api.ServerState - -/** - * Listener interface for events originating from a [Host]. - */ -public interface HostListener { - /** - * This method is invoked when the state of an [instance][server] on [host] changes. - */ - public fun onStateChanged(host: Host, server: Server, newState: ServerState) {} - - /** - * This method is invoked when the state of a [Host] has changed. - */ - public fun onStateChanged(host: Host, newState: HostState) {} -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostModel.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostModel.kt deleted file mode 100644 index 5632a55e..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostModel.kt +++ /dev/null @@ -1,31 +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.service.driver - -/** - * Describes the static machine properties of the host. - * - * @property vcpuCount The number of logical processing cores available for this host. - * @property memorySize The amount of memory available for this host in MB. - */ -public data class HostModel(public val cpuCount: Int, public val memorySize: Long) diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostState.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostState.kt deleted file mode 100644 index 6d85ee2d..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostState.kt +++ /dev/null @@ -1,38 +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.service.driver - -/** - * The state of a host. - */ -public enum class HostState { - /** - * The host is up. - */ - UP, - - /** - * The host is down. - */ - DOWN -} 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 deleted file mode 100644 index 4a8d3046..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt +++ /dev/null @@ -1,68 +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.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 - } - - override fun equals(other: Any?): Boolean = other is Flavor && other.uid == uid - - override fun hashCode(): Int = uid.hashCode() - - override fun toString(): String = "Flavor[uid=$uid,name=$name]" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt deleted file mode 100644 index e0b5c171..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt +++ /dev/null @@ -1,61 +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.service.internal - -import org.opendc.compute.api.Image -import java.util.* - -/** - * An [Image] implementation that is passed to clients but delegates its implementation to another class. - */ -internal class ClientImage(private val delegate: Image) : Image { - override val uid: UUID = delegate.uid - - override var name: String = delegate.name - 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() - refresh() - } - - override suspend fun refresh() { - delegate.refresh() - - name = delegate.name - labels = delegate.labels - meta = delegate.meta - } - - override fun equals(other: Any?): Boolean = other is Image && other.uid == uid - - override fun hashCode(): Int = uid.hashCode() - - override fun toString(): String = "Image[uid=$uid,name=$name]" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt deleted file mode 100644 index f2929bf3..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt +++ /dev/null @@ -1,113 +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.service.internal - -import org.opendc.compute.api.Flavor -import org.opendc.compute.api.Image -import org.opendc.compute.api.Server -import org.opendc.compute.api.ServerState -import org.opendc.compute.api.ServerWatcher -import java.util.* - -/** - * A [Server] implementation that is passed to clients but delegates its implementation to another class. - */ -internal class ClientServer(private val delegate: Server) : Server, ServerWatcher { - private val watchers = mutableListOf<ServerWatcher>() - - override val uid: UUID = delegate.uid - - override var name: String = delegate.name - private set - - override var flavor: Flavor = delegate.flavor - private set - - override var image: Image = delegate.image - 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 var state: ServerState = delegate.state - private set - - override suspend fun start() { - delegate.start() - refresh() - } - - override suspend fun stop() { - delegate.stop() - refresh() - } - - override suspend fun delete() { - delegate.delete() - refresh() - } - - override fun watch(watcher: ServerWatcher) { - if (watchers.isEmpty()) { - delegate.watch(this) - } - - watchers += watcher - } - - override fun unwatch(watcher: ServerWatcher) { - watchers += watcher - - if (watchers.isEmpty()) { - delegate.unwatch(this) - } - } - - override suspend fun refresh() { - delegate.refresh() - - name = delegate.name - flavor = delegate.flavor - image = delegate.image - labels = delegate.labels - meta = delegate.meta - state = delegate.state - } - - override fun onStateChanged(server: Server, newState: ServerState) { - val watchers = watchers - - for (watcher in watchers) { - watcher.onStateChanged(this, newState) - } - } - - override fun equals(other: Any?): Boolean = other is Server && other.uid == uid - - override fun hashCode(): Int = uid.hashCode() - - override fun toString(): String = "Server[uid=$uid,name=$name,state=$state]" -} 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 deleted file mode 100644 index 8af5f86e..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt +++ /dev/null @@ -1,500 +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.service.internal - -import io.opentelemetry.api.metrics.Meter -import kotlinx.coroutines.* -import mu.KotlinLogging -import org.opendc.compute.api.* -import org.opendc.compute.service.ComputeService -import org.opendc.compute.service.driver.Host -import org.opendc.compute.service.driver.HostListener -import org.opendc.compute.service.driver.HostState -import org.opendc.compute.service.scheduler.ComputeScheduler -import org.opendc.utils.TimerScheduler -import java.time.Clock -import java.util.* -import kotlin.coroutines.CoroutineContext -import kotlin.math.max - -/** - * Internal implementation of the OpenDC Compute service. - * - * @param context The [CoroutineContext] to use. - * @param clock The clock instance to keep track of time. - */ -internal class ComputeServiceImpl( - private val context: CoroutineContext, - private val clock: Clock, - private val meter: Meter, - private val scheduler: ComputeScheduler, - private val schedulingQuantum: Long -) : ComputeService, HostListener { - /** - * The [CoroutineScope] of the service bounded by the lifecycle of the service. - */ - private val scope = CoroutineScope(context + Job()) - - /** - * The logger instance of this server. - */ - private val logger = KotlinLogging.logger {} - - /** - * The [Random] instance used to generate unique identifiers for the objects. - */ - private val random = Random(0) - - /** - * A mapping from host to host view. - */ - private val hostToView = mutableMapOf<Host, HostView>() - - /** - * The available hypervisors. - */ - private val availableHosts: MutableSet<HostView> = mutableSetOf() - - /** - * The servers that should be launched by the service. - */ - private val queue: Deque<SchedulingRequest> = ArrayDeque() - - /** - * The active servers in the system. - */ - 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>() - - /** - * The registered servers for this compute service. - */ - private val servers = mutableMapOf<UUID, InternalServer>() - - private var maxCores = 0 - private var maxMemory = 0L - - /** - * The number of servers that have been submitted to the service for provisioning. - */ - private val _submittedServers = meter.longCounterBuilder("servers.submitted") - .setDescription("Number of start requests") - .setUnit("1") - .build() - - /** - * The number of servers that failed to be scheduled. - */ - private val _unscheduledServers = meter.longCounterBuilder("servers.unscheduled") - .setDescription("Number of unscheduled servers") - .setUnit("1") - .build() - - /** - * The number of servers that are waiting to be provisioned. - */ - private val _waitingServers = meter.longUpDownCounterBuilder("servers.waiting") - .setDescription("Number of servers waiting to be provisioned") - .setUnit("1") - .build() - - /** - * The number of servers that are waiting to be provisioned. - */ - private val _runningServers = meter.longUpDownCounterBuilder("servers.active") - .setDescription("Number of servers currently running") - .setUnit("1") - .build() - - /** - * The number of servers that have finished running. - */ - private val _finishedServers = meter.longCounterBuilder("servers.finished") - .setDescription("Number of servers that finished running") - .setUnit("1") - .build() - - /** - * The number of hosts registered at the compute service. - */ - private val _hostCount = meter.longUpDownCounterBuilder("hosts.total") - .setDescription("Number of hosts") - .setUnit("1") - .build() - - /** - * The number of available hosts registered at the compute service. - */ - private val _availableHostCount = meter.longUpDownCounterBuilder("hosts.available") - .setDescription("Number of available hosts") - .setUnit("1") - .build() - - /** - * The [TimerScheduler] to use for scheduling the scheduler cycles. - */ - private var timerScheduler: TimerScheduler<Unit> = TimerScheduler(scope.coroutineContext, clock) - - override val hosts: Set<Host> - get() = hostToView.keys - - override val hostCount: Int - get() = hostToView.size - - override fun newClient(): ComputeClient { - check(scope.isActive) { "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 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" } - - return images.values.map { ClientImage(it) } - } - - override suspend fun findImage(id: UUID): Image? { - check(!isClosed) { "Client is already closed" } - - return images[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) - - images[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(flavors[flavor.uid]) { "Unknown flavor" }, - requireNotNull(images[image.uid]) { "Unknown image" }, - labels.toMutableMap(), - meta.toMutableMap() - ) - - servers[uid] = server - - if (start) { - server.start() - } - - return ClientServer(server) - } - - override suspend fun findServer(id: UUID): Server? { - check(!isClosed) { "Client is already closed" } - - return servers[id]?.let { ClientServer(it) } - } - - override suspend fun queryServers(): List<Server> { - check(!isClosed) { "Client is already closed" } - - return servers.values.map { ClientServer(it) } - } - - override fun close() { - isClosed = true - } - - override fun toString(): String = "ComputeClient" - } - } - - override fun addHost(host: Host) { - // Check if host is already known - if (host in hostToView) { - return - } - - val hv = HostView(host) - maxCores = max(maxCores, host.model.cpuCount) - maxMemory = max(maxMemory, host.model.memorySize) - hostToView[host] = hv - - if (host.state == HostState.UP) { - _availableHostCount.add(1) - availableHosts += hv - } - - scheduler.addHost(hv) - _hostCount.add(1) - host.addListener(this) - } - - override fun removeHost(host: Host) { - val view = hostToView.remove(host) - if (view != null) { - if (availableHosts.remove(view)) { - _availableHostCount.add(-1) - } - scheduler.removeHost(view) - host.removeListener(this) - _hostCount.add(-1) - } - } - - override fun close() { - scope.cancel() - } - - internal fun schedule(server: InternalServer): SchedulingRequest { - logger.debug { "Enqueueing server ${server.uid} to be assigned to host." } - - val request = SchedulingRequest(server) - queue.add(request) - _submittedServers.add(1) - _waitingServers.add(1) - requestSchedulingCycle() - return request - } - - internal fun delete(flavor: InternalFlavor) { - flavors.remove(flavor.uid) - } - - internal fun delete(image: InternalImage) { - images.remove(image.uid) - } - - internal fun delete(server: InternalServer) { - servers.remove(server.uid) - } - - /** - * Indicate that a new scheduling cycle is needed due to a change to the service's state. - */ - private fun requestSchedulingCycle() { - // Bail out in case we have already requested a new cycle or the queue is empty. - if (timerScheduler.isTimerActive(Unit) || queue.isEmpty()) { - return - } - - // We assume that the provisioner runs at a fixed slot every time quantum (e.g t=0, t=60, t=120). - // This is important because the slices of the VMs need to be aligned. - // We calculate here the delay until the next scheduling slot. - val delay = schedulingQuantum - (clock.millis() % schedulingQuantum) - - timerScheduler.startSingleTimer(Unit, delay) { - doSchedule() - } - } - - /** - * Run a single scheduling iteration. - */ - private fun doSchedule() { - while (queue.isNotEmpty()) { - val request = queue.peek() - - if (request.isCancelled) { - queue.poll() - _waitingServers.add(-1) - continue - } - - val server = request.server - val hv = scheduler.select(request.server) - if (hv == null || !hv.host.canFit(server)) { - logger.trace { "Server $server selected for scheduling but no capacity available for it at the moment" } - - if (server.flavor.memorySize > maxMemory || server.flavor.cpuCount > maxCores) { - // Remove the incoming image - queue.poll() - _waitingServers.add(-1) - _unscheduledServers.add(1) - - logger.warn("Failed to spawn $server: does not fit [${clock.millis()}]") - - server.state = ServerState.ERROR - continue - } else { - break - } - } - - val host = hv.host - - // Remove request from queue - queue.poll() - _waitingServers.add(-1) - - logger.info { "Assigned server $server to host $host." } - - // Speculatively update the hypervisor view information to prevent other images in the queue from - // deciding on stale values. - hv.instanceCount++ - hv.provisionedCores += server.flavor.cpuCount - hv.availableMemory -= server.flavor.memorySize // XXX Temporary hack - - scope.launch { - try { - server.host = host - host.spawn(server) - activeServers[server] = host - } catch (e: Throwable) { - logger.error("Failed to deploy VM", e) - - hv.instanceCount-- - hv.provisionedCores -= server.flavor.cpuCount - hv.availableMemory += server.flavor.memorySize - } - } - } - } - - /** - * A request to schedule an [InternalServer] onto one of the [Host]s. - */ - internal data class SchedulingRequest(val server: InternalServer) { - /** - * A flag to indicate that the request is cancelled. - */ - var isCancelled: Boolean = false - } - - override fun onStateChanged(host: Host, newState: HostState) { - when (newState) { - HostState.UP -> { - logger.debug { "[${clock.millis()}] Host ${host.uid} state changed: $newState" } - - val hv = hostToView[host] - if (hv != null) { - // Corner case for when the hypervisor already exists - availableHosts += hv - _availableHostCount.add(1) - } - - // Re-schedule on the new machine - requestSchedulingCycle() - } - HostState.DOWN -> { - logger.debug { "[${clock.millis()}] Host ${host.uid} state changed: $newState" } - - val hv = hostToView[host] ?: return - availableHosts -= hv - _availableHostCount.add(-1) - - requestSchedulingCycle() - } - } - } - - override fun onStateChanged(host: Host, server: Server, newState: ServerState) { - require(server is InternalServer) { "Invalid server type passed to service" } - - if (server.host != host) { - // This can happen when a server is rescheduled and started on another machine, while being deleted from - // the old machine. - return - } - - server.state = newState - - if (newState == ServerState.RUNNING) { - _runningServers.add(1) - } else if (newState == ServerState.TERMINATED || newState == ServerState.DELETED) { - logger.info { "[${clock.millis()}] Server ${server.uid} ${server.name} ${server.flavor} finished." } - - activeServers -= server - _runningServers.add(-1) - _finishedServers.add(1) - - val hv = hostToView[host] - if (hv != null) { - hv.provisionedCores -= server.flavor.cpuCount - hv.instanceCount-- - hv.availableMemory += server.flavor.memorySize - } else { - logger.error { "Unknown host $host" } - } - - // Try to reschedule if needed - requestSchedulingCycle() - } - } -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/HostView.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/HostView.kt deleted file mode 100644 index e2f33f11..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/HostView.kt +++ /dev/null @@ -1,44 +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.service.internal - -import org.opendc.compute.service.ComputeService -import org.opendc.compute.service.driver.Host -import java.util.UUID - -/** - * A view of a [Host] as seen from the [ComputeService] - */ -public class HostView(public val host: Host) { - /** - * The unique identifier of the host. - */ - public val uid: UUID - get() = host.uid - - public var instanceCount: Int = 0 - public var availableMemory: Long = host.model.memorySize - public var provisionedCores: Int = 0 - - override fun toString(): String = "HostView[host=$host]" -} 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 deleted file mode 100644 index b8fb6279..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt +++ /dev/null @@ -1,66 +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.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 Flavor && uid == other.uid - - override fun hashCode(): Int = uid.hashCode() - - override fun toString(): String = "Flavor[uid=$uid,name=$name]" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt deleted file mode 100644 index d9ed5896..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt +++ /dev/null @@ -1,56 +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.service.internal - -import org.opendc.compute.api.Image -import java.util.* - -/** - * Internal stateful representation of an [Image]. - */ -internal class InternalImage( - private val service: ComputeServiceImpl, - override val uid: UUID, - override val name: String, - labels: Map<String, String>, - meta: Map<String, Any> -) : Image { - - 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 Image && uid == other.uid - - override fun hashCode(): Int = uid.hashCode() - - override fun toString(): String = "Image[uid=$uid,name=$name]" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt deleted file mode 100644 index d9d0f3fc..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt +++ /dev/null @@ -1,153 +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.service.internal - -import mu.KotlinLogging -import org.opendc.compute.api.* -import org.opendc.compute.service.driver.Host -import java.util.UUID - -/** - * Internal implementation of the [Server] interface. - */ -internal class InternalServer( - private val service: ComputeServiceImpl, - override val uid: UUID, - override val name: String, - override val flavor: InternalFlavor, - override val image: InternalImage, - override val labels: MutableMap<String, String>, - override val meta: MutableMap<String, Any> -) : Server { - /** - * The logger instance of this server. - */ - private val logger = KotlinLogging.logger {} - - /** - * The watchers of this server object. - */ - private val watchers = mutableListOf<ServerWatcher>() - - /** - * The [Host] that has been assigned to host the server. - */ - internal var host: Host? = null - - /** - * The current scheduling request. - */ - private var request: ComputeServiceImpl.SchedulingRequest? = null - - override suspend fun start() { - when (state) { - ServerState.RUNNING -> { - logger.debug { "User tried to start server but server is already running" } - return - } - ServerState.PROVISIONING -> { - logger.debug { "User tried to start server but request is already pending: doing nothing" } - return - } - ServerState.DELETED -> { - logger.warn { "User tried to start terminated server" } - throw IllegalStateException("Server is terminated") - } - else -> { - logger.info { "User requested to start server $uid" } - state = ServerState.PROVISIONING - assert(request == null) { "Scheduling request already active" } - request = service.schedule(this) - } - } - } - - override suspend fun stop() { - when (state) { - ServerState.PROVISIONING -> { - cancelProvisioningRequest() - state = ServerState.TERMINATED - } - ServerState.RUNNING, ServerState.ERROR -> { - val host = checkNotNull(host) { "Server not running" } - host.stop(this) - } - ServerState.TERMINATED, ServerState.DELETED -> {} // No work needed - } - } - - override suspend fun delete() { - when (state) { - ServerState.PROVISIONING, ServerState.TERMINATED -> { - cancelProvisioningRequest() - service.delete(this) - state = ServerState.DELETED - } - ServerState.RUNNING, ServerState.ERROR -> { - val host = checkNotNull(host) { "Server not running" } - host.delete(this) - service.delete(this) - state = ServerState.DELETED - } - else -> {} // No work needed - } - } - - override fun watch(watcher: ServerWatcher) { - watchers += watcher - } - - override fun unwatch(watcher: ServerWatcher) { - watchers -= watcher - } - - override suspend fun refresh() { - // No-op: this object is the source-of-truth - } - - override var state: ServerState = ServerState.TERMINATED - set(value) { - if (value != field) { - watchers.forEach { it.onStateChanged(this, value) } - } - - field = value - } - - /** - * Cancel the provisioning request if active. - */ - private fun cancelProvisioningRequest() { - val request = request - if (request != null) { - this.request = null - request.isCancelled = true - } - } - - override fun equals(other: Any?): Boolean = other is Server && uid == other.uid - - override fun hashCode(): Int = uid.hashCode() - - override fun toString(): String = "Server[uid=$uid,state=$state]" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt deleted file mode 100644 index a2ab3a2e..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt +++ /dev/null @@ -1,50 +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.service.scheduler - -import org.opendc.compute.api.Server -import org.opendc.compute.service.ComputeService -import org.opendc.compute.service.internal.HostView - -/** - * A generic scheduler interface used by the [ComputeService] to select hosts to place [Server]s on. - */ -public interface ComputeScheduler { - /** - * Register the specified [host] to be used for scheduling. - */ - public fun addHost(host: HostView) - - /** - * Remove the specified [host] to be removed from the scheduling pool. - */ - public fun removeHost(host: HostView) - - /** - * Select a host for the specified [server]. - * - * @param server The server to select a host for. - * @return The host to schedule the server on or `null` if no server is available. - */ - public fun select(server: Server): HostView? -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt deleted file mode 100644 index 0fd5b2a4..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt +++ /dev/null @@ -1,66 +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.service.scheduler - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView -import org.opendc.compute.service.scheduler.filters.HostFilter -import org.opendc.compute.service.scheduler.weights.HostWeigher - -/** - * A [ComputeScheduler] implementation that uses filtering and weighing passes to select - * the host to schedule a [Server] on. - * - * This implementation is based on the filter scheduler from OpenStack Nova. - * See: https://docs.openstack.org/nova/latest/user/filter-scheduler.html - */ -public class FilterScheduler(private val filters: List<HostFilter>, private val weighers: List<Pair<HostWeigher, Double>>) : ComputeScheduler { - /** - * The pool of hosts available to the scheduler. - */ - private val hosts = mutableListOf<HostView>() - - override fun addHost(host: HostView) { - hosts.add(host) - } - - override fun removeHost(host: HostView) { - hosts.remove(host) - } - - override fun select(server: Server): HostView? { - return hosts.asSequence() - .filter { host -> - for (filter in filters) { - if (!filter.test(host, server)) - return@filter false - } - - true - } - .sortedByDescending { host -> - weighers.sumByDouble { (weigher, factor) -> weigher.getWeight(host, server) * factor } - } - .firstOrNull() - } -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt deleted file mode 100644 index 284c1f91..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt +++ /dev/null @@ -1,64 +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.service.scheduler - -import mu.KotlinLogging -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView - -/** - * Policy replaying VM-cluster assignment. - * - * Within each cluster, the active servers on each node determine which node gets - * assigned the VM image. - */ -public class ReplayScheduler(private val vmPlacements: Map<String, String>) : ComputeScheduler { - private val logger = KotlinLogging.logger {} - - /** - * The pool of hosts available to the scheduler. - */ - private val hosts = mutableListOf<HostView>() - - override fun addHost(host: HostView) { - hosts.add(host) - } - - override fun removeHost(host: HostView) { - hosts.remove(host) - } - - override fun select(server: Server): HostView? { - val clusterName = vmPlacements[server.name] - ?: throw IllegalStateException("Could not find placement data in VM placement file for VM ${server.name}") - val machinesInCluster = hosts.filter { it.host.name.contains(clusterName) } - - if (machinesInCluster.isEmpty()) { - logger.info { "Could not find any machines belonging to cluster $clusterName for image ${server.name}, assigning randomly." } - return hosts.maxByOrNull { it.availableMemory } - } - - return machinesInCluster.maxByOrNull { it.availableMemory } - ?: throw IllegalStateException("Cloud not find any machine and could not randomly assign") - } -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeCapabilitiesFilter.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeCapabilitiesFilter.kt deleted file mode 100644 index 072440c5..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeCapabilitiesFilter.kt +++ /dev/null @@ -1,40 +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.service.scheduler.filters - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView - -/** - * A [HostFilter] that checks whether the capabilities provided by the host satisfies the requirements of the server - * flavor. - */ -public class ComputeCapabilitiesFilter : HostFilter { - override fun test(host: HostView, server: Server): Boolean { - val fitsMemory = host.availableMemory >= server.flavor.memorySize - val fitsCpu = host.host.model.cpuCount >= server.flavor.cpuCount - return fitsMemory && fitsCpu - } - - override fun toString(): String = "ComputeCapabilitiesFilter" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt deleted file mode 100644 index fb842415..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt +++ /dev/null @@ -1,38 +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.service.scheduler.filters - -import org.opendc.compute.api.Server -import org.opendc.compute.service.driver.HostState -import org.opendc.compute.service.internal.HostView - -/** - * A [HostFilter] that filters on active hosts. - */ -public class ComputeFilter : HostFilter { - override fun test(host: HostView, server: Server): Boolean { - return host.host.state == HostState.UP - } - - override fun toString(): String = "ComputeFilter" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt deleted file mode 100644 index 9e909ca6..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt +++ /dev/null @@ -1,38 +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.service.scheduler.filters - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView -import org.opendc.compute.service.scheduler.FilterScheduler - -/** - * A filter used by the [FilterScheduler] to filter hosts. - */ -public fun interface HostFilter { - /** - * Test whether the specified [host] should be included in the selection - * for scheduling the specified [server]. - */ - public fun test(host: HostView, server: Server): Boolean -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt deleted file mode 100644 index ed6674b1..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt +++ /dev/null @@ -1,39 +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.service.scheduler.filters - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView - -/** - * A [HostFilter] that filters hosts based on the number of instances on the host. - * - * @param limit The maximum number of instances on the host. - */ -public class InstanceCountFilter(private val limit: Int) : HostFilter { - override fun test(host: HostView, server: Server): Boolean { - return host.instanceCount < limit - } - - override fun toString(): String = "InstanceCountFilter[limit=$limit]" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreMemoryWeigher.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreMemoryWeigher.kt deleted file mode 100644 index 12e6510e..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreMemoryWeigher.kt +++ /dev/null @@ -1,37 +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.service.scheduler.weights - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the available memory per core on the host. - */ -public class CoreMemoryWeigher : HostWeigher { - override fun getWeight(host: HostView, server: Server): Double { - return host.availableMemory.toDouble() / host.host.model.cpuCount - } - - override fun toString(): String = "CoreMemoryWeigher" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt deleted file mode 100644 index d48ee9e0..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt +++ /dev/null @@ -1,37 +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.service.scheduler.weights - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView -import org.opendc.compute.service.scheduler.FilterScheduler - -/** - * An interface used by the [FilterScheduler] to weigh the pool of host for a scheduling request. - */ -public fun interface HostWeigher { - /** - * Obtain the weight of the specified [host] when scheduling the specified [server]. - */ - public fun getWeight(host: HostView, server: Server): Double -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt deleted file mode 100644 index 2ef733e5..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt +++ /dev/null @@ -1,37 +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.service.scheduler.weights - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the number of instances on the host. - */ -public class InstanceCountWeigher : HostWeigher { - override fun getWeight(host: HostView, server: Server): Double { - return host.instanceCount.toDouble() - } - - override fun toString(): String = "InstanceCountWeigher" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/MemoryWeigher.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/MemoryWeigher.kt deleted file mode 100644 index 115d8e4d..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/MemoryWeigher.kt +++ /dev/null @@ -1,37 +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.service.scheduler.weights - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the available memory on the host. - */ -public class MemoryWeigher : HostWeigher { - override fun getWeight(host: HostView, server: Server): Double { - return host.availableMemory.toDouble() - } - - override fun toString(): String = "MemoryWeigher" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/ProvisionedCoresWeigher.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/ProvisionedCoresWeigher.kt deleted file mode 100644 index df5bcd6e..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/ProvisionedCoresWeigher.kt +++ /dev/null @@ -1,37 +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.service.scheduler.weights - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the number of provisioned cores on the host. - */ -public class ProvisionedCoresWeigher : HostWeigher { - override fun getWeight(host: HostView, server: Server): Double { - return host.provisionedCores.toDouble() - } - - override fun toString(): String = "ProvisionedCoresWeigher" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RandomWeigher.kt b/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RandomWeigher.kt deleted file mode 100644 index 1615df3a..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RandomWeigher.kt +++ /dev/null @@ -1,36 +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.service.scheduler.weights - -import org.opendc.compute.api.Server -import org.opendc.compute.service.internal.HostView -import java.util.* - -/** - * A [HostWeigher] that assigns random weights to each host every selection. - */ -public class RandomWeigher(private val random: Random) : HostWeigher { - override fun getWeight(host: HostView, server: Server): Double = random.nextDouble() - - override fun toString(): String = "RandomWeigher" -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt b/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt deleted file mode 100644 index a6258845..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt +++ /dev/null @@ -1,391 +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.service - -import io.mockk.* -import io.opentelemetry.api.metrics.MeterProvider -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNull -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.compute.api.* -import org.opendc.compute.service.driver.Host -import org.opendc.compute.service.driver.HostListener -import org.opendc.compute.service.driver.HostModel -import org.opendc.compute.service.driver.HostState -import org.opendc.compute.service.scheduler.FilterScheduler -import org.opendc.compute.service.scheduler.filters.ComputeCapabilitiesFilter -import org.opendc.compute.service.scheduler.filters.ComputeFilter -import org.opendc.compute.service.scheduler.weights.MemoryWeigher -import org.opendc.simulator.core.SimulationCoroutineScope -import org.opendc.simulator.core.runBlockingSimulation -import java.util.* - -/** - * Test suite for the [ComputeService] interface. - */ -@OptIn(ExperimentalCoroutinesApi::class) -internal class ComputeServiceTest { - lateinit var scope: SimulationCoroutineScope - lateinit var service: ComputeService - - @BeforeEach - fun setUp() { - scope = SimulationCoroutineScope() - val clock = scope.clock - val computeScheduler = FilterScheduler( - filters = listOf(ComputeFilter(), ComputeCapabilitiesFilter()), - weighers = listOf(MemoryWeigher() to -1.0) - ) - val meter = MeterProvider.noop().get("opendc-compute") - service = ComputeService(scope.coroutineContext, clock, meter, computeScheduler) - } - - @Test - fun testClientClose() = scope.runBlockingSimulation { - val client = service.newClient() - - assertEquals(emptyList<Flavor>(), client.queryFlavors()) - assertEquals(emptyList<Image>(), client.queryImages()) - assertEquals(emptyList<Server>(), client.queryServers()) - - client.close() - - assertThrows<IllegalStateException> { client.queryFlavors() } - assertThrows<IllegalStateException> { client.queryImages() } - assertThrows<IllegalStateException> { client.queryServers() } - - assertThrows<IllegalStateException> { client.findFlavor(UUID.randomUUID()) } - assertThrows<IllegalStateException> { client.findImage(UUID.randomUUID()) } - assertThrows<IllegalStateException> { client.findServer(UUID.randomUUID()) } - - assertThrows<IllegalStateException> { client.newFlavor("test", 1, 2) } - assertThrows<IllegalStateException> { client.newImage("test") } - assertThrows<IllegalStateException> { client.newServer("test", mockk(), mockk()) } - } - - @Test - fun testClientCreate() = scope.runBlockingSimulation { - val client = service.newClient() - - val flavor = client.newFlavor("test", 1, 1024) - assertEquals(listOf(flavor), client.queryFlavors()) - assertEquals(flavor, client.findFlavor(flavor.uid)) - val image = client.newImage("test") - assertEquals(listOf(image), client.queryImages()) - assertEquals(image, client.findImage(image.uid)) - val server = client.newServer("test", image, flavor, start = false) - assertEquals(listOf(server), client.queryServers()) - assertEquals(server, client.findServer(server.uid)) - - server.delete() - assertNull(client.findServer(server.uid)) - - image.delete() - assertNull(client.findImage(image.uid)) - - flavor.delete() - assertNull(client.findFlavor(flavor.uid)) - - assertThrows<IllegalStateException> { server.start() } - } - - @Test - fun testClientOnClose() = scope.runBlockingSimulation { - service.close() - assertThrows<IllegalStateException> { - service.newClient() - } - } - - @Test - fun testAddHost() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.UP - - assertEquals(0, service.hostCount) - assertEquals(emptySet<Host>(), service.hosts) - - service.addHost(host) - - verify(exactly = 1) { host.addListener(any()) } - - assertEquals(1, service.hostCount) - assertEquals(1, service.hosts.size) - - service.removeHost(host) - - verify(exactly = 1) { host.removeListener(any()) } - } - - @Test - fun testAddHostDouble() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.DOWN - - assertEquals(0, service.hostCount) - assertEquals(emptySet<Host>(), service.hosts) - - service.addHost(host) - service.addHost(host) - - verify(exactly = 1) { host.addListener(any()) } - } - - @Test - fun testServerStartWithoutEnoughCpus() = scope.runBlockingSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 0) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - server.start() - delay(5 * 60 * 1000) - server.refresh() - assertEquals(ServerState.ERROR, server.state) - } - - @Test - fun testServerStartWithoutEnoughMemory() = scope.runBlockingSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 0, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - server.start() - delay(5 * 60 * 1000) - server.refresh() - assertEquals(ServerState.ERROR, server.state) - } - - @Test - fun testServerStartWithoutEnoughResources() = scope.runBlockingSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - server.start() - delay(5 * 60 * 1000) - server.refresh() - assertEquals(ServerState.ERROR, server.state) - } - - @Test - fun testServerCancelRequest() = scope.runBlockingSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - server.start() - server.stop() - delay(5 * 60 * 1000) - server.refresh() - assertEquals(ServerState.TERMINATED, server.state) - } - - @Test - fun testServerCannotFitOnHost() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.UP - every { host.canFit(any()) } returns false - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - server.start() - delay(10 * 60 * 1000) - server.refresh() - assertEquals(ServerState.PROVISIONING, server.state) - - verify { host.canFit(server) } - } - - @Test - fun testHostAvailableAfterSomeTime() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - val listeners = mutableListOf<HostListener>() - - every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.DOWN - every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } - every { host.canFit(any()) } returns false - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - server.start() - delay(5 * 60 * 1000) - - every { host.state } returns HostState.UP - listeners.forEach { it.onStateChanged(host, HostState.UP) } - - delay(5 * 60 * 1000) - server.refresh() - assertEquals(ServerState.PROVISIONING, server.state) - - verify { host.canFit(server) } - } - - @Test - fun testHostUnavailableAfterSomeTime() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - val listeners = mutableListOf<HostListener>() - - every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.UP - every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } - every { host.canFit(any()) } returns false - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - delay(5 * 60 * 1000) - - every { host.state } returns HostState.DOWN - listeners.forEach { it.onStateChanged(host, HostState.DOWN) } - - server.start() - delay(5 * 60 * 1000) - server.refresh() - assertEquals(ServerState.PROVISIONING, server.state) - - verify(exactly = 0) { host.canFit(server) } - } - - @Test - fun testServerInvalidType() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - val listeners = mutableListOf<HostListener>() - - every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.UP - every { host.canFit(any()) } returns true - every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - assertThrows<IllegalArgumentException> { - listeners.forEach { it.onStateChanged(host, server, ServerState.RUNNING) } - } - } - - @Test - fun testServerDeploy() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - val listeners = mutableListOf<HostListener>() - - every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.UP - every { host.canFit(any()) } returns true - every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - val slot = slot<Server>() - - val watcher = mockk<ServerWatcher>(relaxUnitFun = true) - server.watch(watcher) - - // Start server - server.start() - delay(5 * 60 * 1000) - coVerify { host.spawn(capture(slot), true) } - - listeners.forEach { it.onStateChanged(host, slot.captured, ServerState.RUNNING) } - - server.refresh() - assertEquals(ServerState.RUNNING, server.state) - - verify { watcher.onStateChanged(server, ServerState.RUNNING) } - - // Stop server - listeners.forEach { it.onStateChanged(host, slot.captured, ServerState.TERMINATED) } - - server.refresh() - assertEquals(ServerState.TERMINATED, server.state) - - verify { watcher.onStateChanged(server, ServerState.TERMINATED) } - } - - @Test - fun testServerDeployFailure() = scope.runBlockingSimulation { - val host = mockk<Host>(relaxUnitFun = true) - val listeners = mutableListOf<HostListener>() - - every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4, 2048) - every { host.state } returns HostState.UP - every { host.canFit(any()) } returns true - every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } - coEvery { host.spawn(any(), true) } throws IllegalStateException() - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newServer("test", image, flavor, start = false) - - server.start() - delay(5 * 60 * 1000) - - server.refresh() - assertEquals(ServerState.PROVISIONING, server.state) - } -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalFlavorTest.kt b/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalFlavorTest.kt deleted file mode 100644 index 18d698c6..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalFlavorTest.kt +++ /dev/null @@ -1,80 +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.service - -import io.mockk.* -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test -import org.opendc.compute.api.Flavor -import org.opendc.compute.service.internal.ComputeServiceImpl -import org.opendc.compute.service.internal.InternalFlavor -import java.util.* - -/** - * Test suite for the [InternalFlavor] implementation. - */ -class InternalFlavorTest { - @Test - fun testEquality() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf()) - val b = InternalFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf()) - - assertEquals(a, b) - } - - @Test - fun testEqualityWithDifferentType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf()) - - val b = mockk<Flavor>(relaxUnitFun = true) - every { b.uid } returns uid - - assertEquals(a, b) - } - - @Test - fun testInequalityWithDifferentType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf()) - - val b = mockk<Flavor>(relaxUnitFun = true) - every { b.uid } returns UUID.randomUUID() - - assertNotEquals(a, b) - } - - @Test - fun testInequalityWithIncorrectType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf()) - - assertNotEquals(a, Unit) - } -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalImageTest.kt b/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalImageTest.kt deleted file mode 100644 index e1cb0128..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalImageTest.kt +++ /dev/null @@ -1,81 +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.service - -import io.mockk.* -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test -import org.opendc.compute.api.Image -import org.opendc.compute.service.internal.ComputeServiceImpl -import org.opendc.compute.service.internal.InternalFlavor -import org.opendc.compute.service.internal.InternalImage -import java.util.* - -/** - * Test suite for the [InternalFlavor] implementation. - */ -class InternalImageTest { - @Test - fun testEquality() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalImage(service, uid, "test", mutableMapOf(), mutableMapOf()) - val b = InternalImage(service, uid, "test", mutableMapOf(), mutableMapOf()) - - assertEquals(a, b) - } - - @Test - fun testEqualityWithDifferentType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalImage(service, uid, "test", mutableMapOf(), mutableMapOf()) - - val b = mockk<Image>(relaxUnitFun = true) - every { b.uid } returns uid - - assertEquals(a, b) - } - - @Test - fun testInequalityWithDifferentType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalImage(service, uid, "test", mutableMapOf(), mutableMapOf()) - - val b = mockk<Image>(relaxUnitFun = true) - every { b.uid } returns UUID.randomUUID() - - assertNotEquals(a, b) - } - - @Test - fun testInequalityWithIncorrectType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val a = InternalImage(service, uid, "test", mutableMapOf(), mutableMapOf()) - - assertNotEquals(a, Unit) - } -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt b/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt deleted file mode 100644 index 20ea8d20..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt +++ /dev/null @@ -1,285 +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.service - -import io.mockk.* -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.yield -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.compute.api.Server -import org.opendc.compute.api.ServerState -import org.opendc.compute.service.driver.Host -import org.opendc.compute.service.internal.ComputeServiceImpl -import org.opendc.compute.service.internal.InternalFlavor -import org.opendc.compute.service.internal.InternalImage -import org.opendc.compute.service.internal.InternalServer -import org.opendc.simulator.core.runBlockingSimulation -import java.util.* - -/** - * Test suite for the [InternalServer] implementation. - */ -@OptIn(ExperimentalCoroutinesApi::class) -class InternalServerTest { - @Test - fun testEquality() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val a = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - val b = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - assertEquals(a, b) - } - - @Test - fun testEqualityWithDifferentType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val a = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - val b = mockk<Server>(relaxUnitFun = true) - every { b.uid } returns uid - - assertEquals(a, b) - } - - @Test - fun testInequalityWithDifferentType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val a = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - val b = mockk<Server>(relaxUnitFun = true) - every { b.uid } returns UUID.randomUUID() - - assertNotEquals(a, b) - } - - @Test - fun testInequalityWithIncorrectType() { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val a = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - assertNotEquals(a, Unit) - } - - @Test - fun testStartTerminatedServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - every { service.schedule(any()) } answers { ComputeServiceImpl.SchedulingRequest(it.invocation.args[0] as InternalServer) } - - server.start() - - verify(exactly = 1) { service.schedule(server) } - assertEquals(ServerState.PROVISIONING, server.state) - } - - @Test - fun testStartDeletedServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - server.state = ServerState.DELETED - - assertThrows<IllegalStateException> { server.start() } - } - - @Test - fun testStartProvisioningServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - server.state = ServerState.PROVISIONING - - server.start() - - assertEquals(ServerState.PROVISIONING, server.state) - } - - @Test - fun testStartRunningServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - server.state = ServerState.RUNNING - - server.start() - - assertEquals(ServerState.RUNNING, server.state) - } - - @Test - fun testStopProvisioningServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - val request = ComputeServiceImpl.SchedulingRequest(server) - - every { service.schedule(any()) } returns request - - server.start() - server.stop() - - assertTrue(request.isCancelled) - assertEquals(ServerState.TERMINATED, server.state) - } - - @Test - fun testStopTerminatedServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - server.state = ServerState.TERMINATED - server.stop() - - assertEquals(ServerState.TERMINATED, server.state) - } - - @Test - fun testStopDeletedServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - server.state = ServerState.DELETED - server.stop() - - assertEquals(ServerState.DELETED, server.state) - } - - @Test - fun testStopRunningServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>() - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - val host = mockk<Host>(relaxUnitFun = true) - - server.state = ServerState.RUNNING - server.host = host - server.stop() - yield() - - coVerify { host.stop(server) } - } - - @Test - fun testDeleteProvisioningServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - val request = ComputeServiceImpl.SchedulingRequest(server) - - every { service.schedule(any()) } returns request - - server.start() - server.delete() - - assertTrue(request.isCancelled) - assertEquals(ServerState.DELETED, server.state) - verify { service.delete(server) } - } - - @Test - fun testDeleteTerminatedServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - server.state = ServerState.TERMINATED - server.delete() - - assertEquals(ServerState.DELETED, server.state) - - verify { service.delete(server) } - } - - @Test - fun testDeleteDeletedServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - - server.state = ServerState.DELETED - server.delete() - - assertEquals(ServerState.DELETED, server.state) - } - - @Test - fun testDeleteRunningServer() = runBlockingSimulation { - val service = mockk<ComputeServiceImpl>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockk<InternalFlavor>() - val image = mockk<InternalImage>() - val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf()) - val host = mockk<Host>(relaxUnitFun = true) - - server.state = ServerState.RUNNING - server.host = host - server.delete() - yield() - - coVerify { host.delete(server) } - verify { service.delete(server) } - } -} diff --git a/simulator/opendc-compute/opendc-compute-service/src/test/resources/log4j2.xml b/simulator/opendc-compute/opendc-compute-service/src/test/resources/log4j2.xml deleted file mode 100644 index 0dfb75f2..00000000 --- a/simulator/opendc-compute/opendc-compute-service/src/test/resources/log4j2.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ 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. - --> - -<Configuration status="WARN" packages="org.apache.logging.log4j.core"> - <Appenders> - <Console name="Console" target="SYSTEM_OUT"> - <PatternLayout pattern="%d{HH:mm:ss.SSS} [%highlight{%-5level}] %logger{36} - %msg%n" disableAnsi="false"/> - </Console> - </Appenders> - <Loggers> - <Logger name="org.opendc" level="trace" additivity="false"> - <AppenderRef ref="Console"/> - </Logger> - <Root level="info"> - <AppenderRef ref="Console"/> - </Root> - </Loggers> -</Configuration> diff --git a/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts b/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts deleted file mode 100644 index 3bf8a114..00000000 --- a/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts +++ /dev/null @@ -1,43 +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. - */ - -description = "Simulator for OpenDC Compute" - -/* Build configuration */ -plugins { - `kotlin-library-conventions` - `testing-conventions` - `jacoco-conventions` -} - -dependencies { - api(platform(project(":opendc-platform"))) - api(project(":opendc-compute:opendc-compute-service")) - api(project(":opendc-simulator:opendc-simulator-compute")) - api(project(":opendc-simulator:opendc-simulator-failures")) - implementation(project(":opendc-utils")) - implementation("io.github.microutils:kotlin-logging") - - testImplementation(project(":opendc-simulator:opendc-simulator-core")) - testImplementation(project(":opendc-telemetry:opendc-telemetry-sdk")) - testRuntimeOnly("org.slf4j:slf4j-simple:${versions.slf4j}") -} 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 deleted file mode 100644 index 6d87e444..00000000 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt +++ /dev/null @@ -1,423 +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 io.opentelemetry.api.metrics.Meter -import io.opentelemetry.api.metrics.common.Labels -import kotlinx.coroutines.* -import mu.KotlinLogging -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.simulator.compute.* -import org.opendc.simulator.compute.cpufreq.PerformanceScalingGovernor -import org.opendc.simulator.compute.cpufreq.ScalingDriver -import org.opendc.simulator.compute.cpufreq.ScalingGovernor -import org.opendc.simulator.compute.cpufreq.SimpleScalingDriver -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.power.ConstantPowerModel -import org.opendc.simulator.compute.power.PowerModel -import org.opendc.simulator.failures.FailureDomain -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( - override val uid: UUID, - override val name: String, - model: SimMachineModel, - override val meta: Map<String, Any>, - context: CoroutineContext, - clock: Clock, - meter: Meter, - hypervisor: SimHypervisorProvider, - scalingGovernor: ScalingGovernor, - scalingDriver: ScalingDriver, - private val mapper: SimWorkloadMapper = SimMetaWorkloadMapper(), -) : Host, FailureDomain, AutoCloseable { - - public constructor( - uid: UUID, - name: String, - model: SimMachineModel, - meta: Map<String, Any>, - context: CoroutineContext, - clock: Clock, - meter: Meter, - hypervisor: SimHypervisorProvider, - powerModel: PowerModel = ConstantPowerModel(0.0), - mapper: SimWorkloadMapper = SimMetaWorkloadMapper(), - ) : this(uid, name, model, meta, context, clock, meter, hypervisor, PerformanceScalingGovernor(), SimpleScalingDriver(powerModel), mapper) - - /** - * The [CoroutineScope] of the host bounded by the lifecycle of the host. - */ - override val scope: CoroutineScope = CoroutineScope(context + Job()) - - /** - * The logger instance of this server. - */ - private val logger = KotlinLogging.logger {} - - /** - * The event listeners registered with this host. - */ - private val listeners = mutableListOf<HostListener>() - - /** - * Current total memory use of the images on this hypervisor. - */ - private var availableMemory: Long = model.memory.map { it.size }.sum() - - /** - * The machine to run on. - */ - public val machine: SimBareMetalMachine = SimBareMetalMachine(context, clock, model, scalingGovernor, scalingDriver) - - /** - * The hypervisor to run multiple workloads. - */ - public val hypervisor: SimHypervisor = hypervisor.create( - object : SimHypervisor.Listener { - override fun onSliceFinish( - hypervisor: SimHypervisor, - requestedWork: Long, - grantedWork: Long, - overcommittedWork: Long, - interferedWork: Long, - cpuUsage: Double, - cpuDemand: Double - ) { - - _batch.put(_cpuWork, requestedWork.toDouble()) - _batch.put(_cpuWorkGranted, grantedWork.toDouble()) - _batch.put(_cpuWorkOvercommit, overcommittedWork.toDouble()) - _batch.put(_cpuWorkInterference, interferedWork.toDouble()) - _batch.put(_cpuUsage, cpuUsage) - _batch.put(_cpuDemand, cpuDemand) - _batch.put(_cpuPower, machine.powerDraw) - _batch.record() - } - } - ) - - /** - * The virtual machines running on the hypervisor. - */ - private val guests = HashMap<Server, Guest>() - - override val state: HostState - get() = _state - private var _state: HostState = HostState.DOWN - set(value) { - if (value != field) { - listeners.forEach { it.onStateChanged(this, value) } - } - field = value - } - - override val model: HostModel = HostModel(model.cpus.size, model.memory.map { it.size }.sum()) - - /** - * The number of guests on the host. - */ - private val _guests = meter.longUpDownCounterBuilder("guests.total") - .setDescription("Number of guests") - .setUnit("1") - .build() - .bind(Labels.of("host", uid.toString())) - - /** - * The number of active guests on the host. - */ - private val _activeGuests = meter.longUpDownCounterBuilder("guests.active") - .setDescription("Number of active guests") - .setUnit("1") - .build() - .bind(Labels.of("host", uid.toString())) - - /** - * The CPU usage on the host. - */ - private val _cpuUsage = meter.doubleValueRecorderBuilder("cpu.usage") - .setDescription("The amount of CPU resources used by the host") - .setUnit("MHz") - .build() - - /** - * The CPU demand on the host. - */ - private val _cpuDemand = meter.doubleValueRecorderBuilder("cpu.demand") - .setDescription("The amount of CPU resources the guests would use if there were no CPU contention or CPU limits") - .setUnit("MHz") - .build() - - /** - * The requested work for the CPU. - */ - private val _cpuPower = meter.doubleValueRecorderBuilder("power.usage") - .setDescription("The amount of power used by the CPU") - .setUnit("W") - .build() - - /** - * The requested work for the CPU. - */ - private val _cpuWork = meter.doubleValueRecorderBuilder("cpu.work.total") - .setDescription("The amount of work supplied to the CPU") - .setUnit("1") - .build() - - /** - * The work actually performed by the CPU. - */ - private val _cpuWorkGranted = meter.doubleValueRecorderBuilder("cpu.work.granted") - .setDescription("The amount of work performed by the CPU") - .setUnit("1") - .build() - - /** - * The work that could not be performed by the CPU due to overcommitting resource. - */ - private val _cpuWorkOvercommit = meter.doubleValueRecorderBuilder("cpu.work.overcommit") - .setDescription("The amount of work not performed by the CPU due to overcommitment") - .setUnit("1") - .build() - - /** - * The work that could not be performed by the CPU due to interference. - */ - private val _cpuWorkInterference = meter.doubleValueRecorderBuilder("cpu.work.interference") - .setDescription("The amount of work not performed by the CPU due to interference") - .setUnit("1") - .build() - - /** - * The batch recorder used to record multiple metrics atomically. - */ - private val _batch = meter.newBatchRecorder("host", uid.toString()) - - 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 = machine.model.cpus.size >= server.flavor.cpuCount - val canFit = hypervisor.canFit(server.flavor.toMachineModel()) - - return sufficientMemory && enoughCpus && canFit - } - - override suspend fun spawn(server: Server, start: Boolean) { - // Return if the server already exists on this host - if (server in this) { - return - } - - require(canFit(server)) { "Server does not fit" } - val guest = Guest(server, hypervisor.createMachine(server.flavor.toMachineModel())) - guests[server] = guest - _guests.add(1) - - if (start) { - guest.start() - } - } - - override fun contains(server: Server): Boolean { - return server in guests - } - - override suspend fun start(server: Server) { - val guest = requireNotNull(guests[server]) { "Unknown server ${server.uid} at host $uid" } - guest.start() - } - - override suspend fun stop(server: Server) { - val guest = requireNotNull(guests[server]) { "Unknown server ${server.uid} at host $uid" } - guest.stop() - } - - override suspend fun delete(server: Server) { - val guest = guests.remove(server) ?: return - guest.terminate() - _guests.add(-1) - } - - override fun addListener(listener: HostListener) { - listeners.add(listener) - } - - override fun removeListener(listener: HostListener) { - listeners.remove(listener) - } - - override fun close() { - scope.cancel() - machine.close() - } - - override fun toString(): String = "SimHost[uid=$uid,name=$name,model=$model]" - - /** - * Convert flavor to machine model. - */ - private fun Flavor.toMachineModel(): SimMachineModel { - 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)) - - return SimMachineModel(processingUnits, memoryUnits) - } - - private fun onGuestStart(vm: Guest) { - guests.forEach { (_, guest) -> - if (guest.state == ServerState.RUNNING) { - vm.performanceInterferenceModel?.onStart(vm.server.image.name) - } - } - - _activeGuests.add(1) - listeners.forEach { it.onStateChanged(this, vm.server, vm.state) } - } - - private fun onGuestStop(vm: Guest) { - guests.forEach { (_, guest) -> - if (guest.state == ServerState.RUNNING) { - vm.performanceInterferenceModel?.onStop(vm.server.image.name) - } - } - - _activeGuests.add(-1) - listeners.forEach { it.onStateChanged(this, vm.server, vm.state) } - } - - override suspend fun fail() { - _state = HostState.DOWN - } - - override suspend fun recover() { - _state = HostState.UP - } - - /** - * A virtual machine instance that the driver manages. - */ - private inner class Guest(val server: Server, val machine: SimMachine) { - val performanceInterferenceModel: PerformanceInterferenceModel? = server.meta[IMAGE_PERF_INTERFERENCE_MODEL] as? PerformanceInterferenceModel? - - var state: ServerState = ServerState.TERMINATED - - suspend fun start() { - when (state) { - ServerState.TERMINATED -> { - logger.info { "User requested to start server ${server.uid}" } - launch() - } - ServerState.RUNNING -> return - ServerState.DELETED -> { - logger.warn { "User tried to start terminated server" } - throw IllegalArgumentException("Server is terminated") - } - else -> assert(false) { "Invalid state transition" } - } - } - - suspend fun stop() { - when (state) { - ServerState.RUNNING, ServerState.ERROR -> { - val job = job ?: throw IllegalStateException("Server should be active") - job.cancel() - job.join() - } - ServerState.TERMINATED, ServerState.DELETED -> return - else -> assert(false) { "Invalid state transition" } - } - } - - suspend fun terminate() { - stop() - state = ServerState.DELETED - } - - private var job: Job? = null - - private suspend fun launch() = suspendCancellableCoroutine<Unit> { cont -> - assert(job == null) { "Concurrent job running" } - val workload = mapper.createWorkload(server) - - job = scope.launch { - delay(1) // TODO Introduce boot time - init() - cont.resume(Unit) - try { - machine.run(workload, mapOf("driver" to this@SimHost, "server" to server)) - exit(null) - } catch (cause: Throwable) { - exit(cause) - } finally { - machine.close() - job = null - } - } - } - - private fun init() { - state = ServerState.RUNNING - onGuestStart(this) - } - - private fun exit(cause: Throwable?) { - state = - if (cause == null) - ServerState.TERMINATED - else - ServerState.ERROR - - availableMemory += server.flavor.memorySize - onGuestStop(this) - } - } -} diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimMetaWorkloadMapper.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimMetaWorkloadMapper.kt deleted file mode 100644 index c05f1a2c..00000000 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimMetaWorkloadMapper.kt +++ /dev/null @@ -1,35 +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 org.opendc.compute.api.Server -import org.opendc.simulator.compute.workload.SimWorkload - -/** - * A [SimWorkloadMapper] that maps a [Server] to a workload via the meta-data. - */ -public class SimMetaWorkloadMapper(private val key: String = "workload") : SimWorkloadMapper { - override fun createWorkload(server: Server): SimWorkload { - return requireNotNull(server.meta[key] ?: server.image.meta[key]) as SimWorkload - } -} diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadMapper.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadMapper.kt deleted file mode 100644 index 7082c5cf..00000000 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadMapper.kt +++ /dev/null @@ -1,36 +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 org.opendc.compute.api.Server -import org.opendc.simulator.compute.workload.SimWorkload - -/** - * A [SimWorkloadMapper] is responsible for mapping a [Server] and [Image] to a [SimWorkload] that can be simulated. - */ -public fun interface SimWorkloadMapper { - /** - * Map the specified [server] to a [SimWorkload] that can be simulated. - */ - public fun createWorkload(server: Server): SimWorkload -} 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 deleted file mode 100644 index 5594fd59..00000000 --- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt +++ /dev/null @@ -1,227 +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 io.opentelemetry.api.metrics.MeterProvider -import io.opentelemetry.sdk.common.CompletableResultCode -import io.opentelemetry.sdk.metrics.SdkMeterProvider -import io.opentelemetry.sdk.metrics.data.MetricData -import io.opentelemetry.sdk.metrics.export.MetricExporter -import io.opentelemetry.sdk.metrics.export.MetricProducer -import kotlinx.coroutines.* -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.Flavor -import org.opendc.compute.api.Image -import org.opendc.compute.api.Server -import org.opendc.compute.api.ServerState -import org.opendc.compute.api.ServerWatcher -import org.opendc.compute.service.driver.Host -import org.opendc.compute.service.driver.HostListener -import org.opendc.simulator.compute.SimFairShareHypervisorProvider -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.SimTraceWorkload -import org.opendc.simulator.core.runBlockingSimulation -import org.opendc.telemetry.sdk.metrics.export.CoroutineMetricReader -import org.opendc.telemetry.sdk.toOtelClock -import java.util.UUID -import kotlin.coroutines.resume - -/** - * Basic test-suite for the hypervisor. - */ -@OptIn(ExperimentalCoroutinesApi::class) -internal class SimHostTest { - private lateinit var machineModel: SimMachineModel - - @BeforeEach - fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - - machineModel = SimMachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } - ) - } - - /** - * Test overcommitting of resources by the hypervisor. - */ - @Test - fun testOvercommitted() = runBlockingSimulation { - var requestedWork = 0L - var grantedWork = 0L - var overcommittedWork = 0L - - val meterProvider: MeterProvider = SdkMeterProvider - .builder() - .setClock(clock.toOtelClock()) - .build() - - val virtDriver = SimHost(UUID.randomUUID(), "test", machineModel, emptyMap(), coroutineContext, clock, meterProvider.get("opendc-compute-simulator"), SimFairShareHypervisorProvider()) - val duration = 5 * 60L - val vmImageA = MockImage( - UUID.randomUUID(), - "<unnamed>", - emptyMap(), - mapOf( - "workload" to SimTraceWorkload( - sequenceOf( - SimTraceWorkload.Fragment(duration * 1000, 2 * 28.0, 2), - SimTraceWorkload.Fragment(duration * 1000, 2 * 3500.0, 2), - SimTraceWorkload.Fragment(duration * 1000, 0.0, 2), - SimTraceWorkload.Fragment(duration * 1000, 2 * 183.0, 2) - ), - ) - ) - ) - val vmImageB = MockImage( - UUID.randomUUID(), - "<unnamed>", - emptyMap(), - mapOf( - "workload" to SimTraceWorkload( - sequenceOf( - SimTraceWorkload.Fragment(duration * 1000, 2 * 28.0, 2), - SimTraceWorkload.Fragment(duration * 1000, 2 * 3100.0, 2), - SimTraceWorkload.Fragment(duration * 1000, 0.0, 2), - SimTraceWorkload.Fragment(duration * 1000, 2 * 73.0, 2) - ) - ) - ) - ) - - val flavor = MockFlavor(2, 0) - - // Setup metric reader - val reader = CoroutineMetricReader( - this, listOf(meterProvider as MetricProducer), - object : MetricExporter { - override fun export(metrics: Collection<MetricData>): CompletableResultCode { - val metricsByName = metrics.associateBy { it.name } - requestedWork += metricsByName.getValue("cpu.work.total").doubleSummaryData.points.first().sum.toLong() - grantedWork += metricsByName.getValue("cpu.work.granted").doubleSummaryData.points.first().sum.toLong() - overcommittedWork += metricsByName.getValue("cpu.work.overcommit").doubleSummaryData.points.first().sum.toLong() - return CompletableResultCode.ofSuccess() - } - - override fun flush(): CompletableResultCode = CompletableResultCode.ofSuccess() - - override fun shutdown(): CompletableResultCode = CompletableResultCode.ofSuccess() - }, - exportInterval = duration * 1000 - ) - - coroutineScope { - launch { virtDriver.spawn(MockServer(UUID.randomUUID(), "a", flavor, vmImageA)) } - launch { virtDriver.spawn(MockServer(UUID.randomUUID(), "b", flavor, vmImageB)) } - - suspendCancellableCoroutine<Unit> { cont -> - virtDriver.addListener(object : HostListener { - private var finished = 0 - - override fun onStateChanged(host: Host, server: Server, newState: ServerState) { - if (newState == ServerState.TERMINATED && ++finished == 2) { - cont.resume(Unit) - } - } - }) - } - } - - // Ensure last cycle is collected - delay(1000 * duration) - virtDriver.close() - reader.close() - - assertAll( - { assertEquals(4197600, requestedWork, "Requested work does not match") }, - { assertEquals(2157600, grantedWork, "Granted work does not match") }, - { assertEquals(2040000, overcommittedWork, "Overcommitted work does not match") }, - { assertEquals(1500001, clock.millis()) } - ) - } - - 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, - override val labels: Map<String, String>, - override val meta: Map<String, Any> - ) : Image { - override suspend fun delete() { - throw NotImplementedError() - } - - override suspend fun refresh() { - throw NotImplementedError() - } - } - - private class MockServer( - override val uid: UUID, - override val name: String, - override val flavor: Flavor, - override val image: Image - ) : Server { - override val labels: Map<String, String> = emptyMap() - - override val meta: Map<String, Any> = emptyMap() - - override val state: ServerState = ServerState.TERMINATED - - override suspend fun start() {} - - override suspend fun stop() {} - - override suspend fun delete() {} - - override fun watch(watcher: ServerWatcher) {} - - override fun unwatch(watcher: ServerWatcher) {} - - override suspend fun refresh() {} - } -} |
