summaryrefslogtreecommitdiff
path: root/opendc-compute/opendc-compute-service/src
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-compute/opendc-compute-service/src')
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt19
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt35
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestCpuStats.kt44
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestSystemStats.kt39
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostCpuStats.kt47
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostSystemStats.kt51
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt5
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt43
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt3
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/telemetry/SchedulerStats.kt46
-rw-r--r--opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt9
-rw-r--r--opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt2
12 files changed, 321 insertions, 22 deletions
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt
index 2a1fbaa0..3a6baaa1 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt
@@ -25,9 +25,11 @@ package org.opendc.compute.service
import io.opentelemetry.api.metrics.Meter
import io.opentelemetry.api.metrics.MeterProvider
import org.opendc.compute.api.ComputeClient
+import org.opendc.compute.api.Server
import org.opendc.compute.service.driver.Host
import org.opendc.compute.service.internal.ComputeServiceImpl
import org.opendc.compute.service.scheduler.ComputeScheduler
+import org.opendc.compute.service.telemetry.SchedulerStats
import java.time.Clock
import java.time.Duration
import kotlin.coroutines.CoroutineContext
@@ -37,16 +39,11 @@ import kotlin.coroutines.CoroutineContext
*/
public interface ComputeService : AutoCloseable {
/**
- * The hosts that are used by the compute service.
+ * The hosts that are registered with 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
@@ -66,6 +63,16 @@ public interface ComputeService : AutoCloseable {
*/
public override fun close()
+ /**
+ * Lookup the [Host] that currently hosts the specified [server].
+ */
+ public fun lookupHost(server: Server): Host?
+
+ /**
+ * Collect the statistics about the scheduler component of this service.
+ */
+ public fun getSchedulerStats(): SchedulerStats
+
public companion object {
/**
* Construct a new [ComputeService] implementation.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt
index bed15dfd..67b144d9 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt
@@ -23,6 +23,10 @@
package org.opendc.compute.service.driver
import org.opendc.compute.api.Server
+import org.opendc.compute.service.driver.telemetry.GuestCpuStats
+import org.opendc.compute.service.driver.telemetry.GuestSystemStats
+import org.opendc.compute.service.driver.telemetry.HostCpuStats
+import org.opendc.compute.service.driver.telemetry.HostSystemStats
import java.util.*
/**
@@ -55,6 +59,11 @@ public interface Host {
public val meta: Map<String, Any>
/**
+ * The [Server] instances known to the host.
+ */
+ public val instances: Set<Server>
+
+ /**
* Determine whether the specified [instance][server] can still fit on this host.
*/
public fun canFit(server: Server): Boolean
@@ -100,4 +109,30 @@ public interface Host {
* Remove a [HostListener] from this host.
*/
public fun removeListener(listener: HostListener)
+
+ /**
+ * Query the system statistics of the host.
+ */
+ public fun getSystemStats(): HostSystemStats
+
+ /**
+ * Query the system statistics of a [Server] that is located on this host.
+ *
+ * @param server The [Server] to obtain the system statistics of.
+ * @throws IllegalArgumentException if the server is not present on the host.
+ */
+ public fun getSystemStats(server: Server): GuestSystemStats
+
+ /**
+ * Query the CPU statistics of the host.
+ */
+ public fun getCpuStats(): HostCpuStats
+
+ /**
+ * Query the CPU statistics of a [Server] that is located on this host.
+ *
+ * @param server The [Server] to obtain the CPU statistics of.
+ * @throws IllegalArgumentException if the server is not present on the host.
+ */
+ public fun getCpuStats(server: Server): GuestCpuStats
}
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestCpuStats.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestCpuStats.kt
new file mode 100644
index 00000000..b5d63471
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestCpuStats.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 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.telemetry
+
+/**
+ * Statistics about the CPUs of a guest.
+ *
+ * @property activeTime The cumulative time (in seconds) that the CPUs of the guest were actively running.
+ * @property idleTime The cumulative time (in seconds) the CPUs of the guest were idle.
+ * @property stealTime The cumulative CPU time (in seconds) that the guest was ready to run, but not granted time by the host.
+ * @property lostTime The cumulative CPU time (in seconds) that was lost due to interference with other machines.
+ * @property capacity The available CPU capacity of the guest (in MHz).
+ * @property usage Amount of CPU resources (in MHz) actually used by the guest.
+ * @property utilization Utilization of the CPU resources (in %) relative to the total CPU capacity.
+ */
+public data class GuestCpuStats(
+ val activeTime: Long,
+ val idleTime: Long,
+ val stealTime: Long,
+ val lostTime: Long,
+ val capacity: Double,
+ val usage: Double,
+ val utilization: Double
+)
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestSystemStats.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestSystemStats.kt
new file mode 100644
index 00000000..b3958473
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestSystemStats.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022 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.telemetry
+
+import java.time.Duration
+import java.time.Instant
+
+/**
+ * System-level statistics of a guest.
+ *
+ * @property uptime The cumulative uptime of the guest since last boot (in ms).
+ * @property downtime The cumulative downtime of the guest since last boot (in ms).
+ * @property bootTime The time at which the guest booted.
+ */
+public data class GuestSystemStats(
+ val uptime: Duration,
+ val downtime: Duration,
+ val bootTime: Instant
+)
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostCpuStats.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostCpuStats.kt
new file mode 100644
index 00000000..55e23c0e
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostCpuStats.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022 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.telemetry
+
+/**
+ * Statistics about the CPUs of a host.
+ *
+ * @property activeTime The cumulative time (in seconds) that the CPUs of the host were actively running.
+ * @property idleTime The cumulative time (in seconds) the CPUs of the host were idle.
+ * @property stealTime The cumulative CPU time (in seconds) that virtual machines were ready to run, but were not able to.
+ * @property lostTime The cumulative CPU time (in seconds) that was lost due to interference between virtual machines.
+ * @property capacity The available CPU capacity of the host (in MHz).
+ * @property demand Amount of CPU resources (in MHz) the guests would use if there were no CPU contention or CPU
+ * limits.
+ * @property usage Amount of CPU resources (in MHz) actually used by the host.
+ * @property utilization Utilization of the CPU resources (in %) relative to the total CPU capacity.
+ */
+public data class HostCpuStats(
+ val activeTime: Long,
+ val idleTime: Long,
+ val stealTime: Long,
+ val lostTime: Long,
+ val capacity: Double,
+ val demand: Double,
+ val usage: Double,
+ val utilization: Double
+)
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostSystemStats.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostSystemStats.kt
new file mode 100644
index 00000000..1c07023f
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostSystemStats.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022 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.telemetry
+
+import java.time.Duration
+import java.time.Instant
+
+/**
+ * System-level statistics of a host.
+
+ * @property uptime The cumulative uptime of the host since last boot (in ms).
+ * @property downtime The cumulative downtime of the host since last boot (in ms).
+ * @property bootTime The time at which the server started.
+ * @property powerUsage Instantaneous power usage of the system (in W).
+ * @property energyUsage The cumulative energy usage of the system (in J).
+ * @property guestsTerminated The number of guests that are in a terminated state.
+ * @property guestsRunning The number of guests that are in a running state.
+ * @property guestsError The number of guests that are in an error state.
+ * @property guestsInvalid The number of guests that are in an unknown state.
+ */
+public data class HostSystemStats(
+ val uptime: Duration,
+ val downtime: Duration,
+ val bootTime: Instant,
+ val powerUsage: Double,
+ val energyUsage: Double,
+ val guestsTerminated: Int,
+ val guestsRunning: Int,
+ val guestsError: Int,
+ val guestsInvalid: Int,
+)
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt
index f2929bf3..45775640 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt
@@ -27,6 +27,7 @@ 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.time.Instant
import java.util.*
/**
@@ -55,6 +56,9 @@ internal class ClientServer(private val delegate: Server) : Server, ServerWatche
override var state: ServerState = delegate.state
private set
+ override var launchedAt: Instant? = null
+ private set
+
override suspend fun start() {
delegate.start()
refresh()
@@ -95,6 +99,7 @@ internal class ClientServer(private val delegate: Server) : Server, ServerWatche
labels = delegate.labels
meta = delegate.meta
state = delegate.state
+ launchedAt = delegate.launchedAt
}
override fun onStateChanged(server: Server, newState: ServerState) {
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt
index 144b6573..e8664e5c 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt
@@ -36,8 +36,10 @@ 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.compute.service.telemetry.SchedulerStats
import java.time.Clock
import java.time.Duration
+import java.time.Instant
import java.util.*
import kotlin.coroutines.CoroutineContext
import kotlin.math.max
@@ -126,6 +128,9 @@ internal class ComputeServiceImpl(
private val _schedulingAttemptsSuccessAttr = Attributes.of(AttributeKey.stringKey("result"), "success")
private val _schedulingAttemptsFailureAttr = Attributes.of(AttributeKey.stringKey("result"), "failure")
private val _schedulingAttemptsErrorAttr = Attributes.of(AttributeKey.stringKey("result"), "error")
+ private var _attemptsSuccess = 0L
+ private var _attemptsFailure = 0L
+ private var _attemptsError = 0L
/**
* The response time of the service.
@@ -145,6 +150,8 @@ internal class ComputeServiceImpl(
.build()
private val _serversPendingAttr = Attributes.of(AttributeKey.stringKey("state"), "pending")
private val _serversActiveAttr = Attributes.of(AttributeKey.stringKey("state"), "active")
+ private var _serversPending = 0
+ private var _serversActive = 0
/**
* The [Pacer] to use for scheduling the scheduler cycles.
@@ -154,9 +161,6 @@ internal class ComputeServiceImpl(
override val hosts: Set<Host>
get() = hostToView.keys
- override val hostCount: Int
- get() = hostToView.size
-
init {
val upState = Attributes.of(AttributeKey.stringKey("state"), "up")
val downState = Attributes.of(AttributeKey.stringKey("state"), "down")
@@ -165,7 +169,7 @@ internal class ComputeServiceImpl(
.setDescription("Number of hosts registered with the scheduler")
.setUnit("1")
.buildWithCallback { result ->
- val total = hostCount
+ val total = hosts.size
val available = availableHosts.size.toLong()
result.record(available, upState)
@@ -322,17 +326,35 @@ internal class ComputeServiceImpl(
}
}
+ override fun lookupHost(server: Server): Host? {
+ val internal = requireNotNull(servers[server.uid]) { "Invalid server passed to lookupHost" }
+ return internal.host
+ }
+
override fun close() {
scope.cancel()
}
+ override fun getSchedulerStats(): SchedulerStats {
+ return SchedulerStats(
+ availableHosts.size,
+ hostToView.size - availableHosts.size,
+ _attemptsSuccess,
+ _attemptsFailure,
+ _attemptsError,
+ _serversPending,
+ _serversActive
+ )
+ }
+
internal fun schedule(server: InternalServer): SchedulingRequest {
logger.debug { "Enqueueing server ${server.uid} to be assigned to host." }
val now = clock.millis()
val request = SchedulingRequest(server, now)
- server.lastProvisioningTimestamp = now
+ server.launchedAt = Instant.ofEpochMilli(now)
queue.add(request)
+ _serversPending++
_servers.add(1, _serversPendingAttr)
requestSchedulingCycle()
return request
@@ -371,6 +393,7 @@ internal class ComputeServiceImpl(
if (request.isCancelled) {
queue.poll()
+ _serversPending--
_servers.add(-1, _serversPendingAttr)
continue
}
@@ -383,7 +406,9 @@ internal class ComputeServiceImpl(
if (server.flavor.memorySize > maxMemory || server.flavor.cpuCount > maxCores) {
// Remove the incoming image
queue.poll()
+ _serversPending--
_servers.add(-1, _serversPendingAttr)
+ _attemptsFailure++
_schedulingAttempts.add(1, _schedulingAttemptsFailureAttr)
logger.warn { "Failed to spawn $server: does not fit [${clock.instant()}]" }
@@ -399,6 +424,7 @@ internal class ComputeServiceImpl(
// Remove request from queue
queue.poll()
+ _serversPending--
_servers.add(-1, _serversPendingAttr)
_schedulingLatency.record(now - request.submitTime, server.attributes)
@@ -417,6 +443,8 @@ internal class ComputeServiceImpl(
activeServers[server] = host
_servers.add(1, _serversActiveAttr)
+ _serversActive++
+ _attemptsSuccess++
_schedulingAttempts.add(1, _schedulingAttemptsSuccessAttr)
} catch (e: Throwable) {
logger.error(e) { "Failed to deploy VM" }
@@ -425,6 +453,7 @@ internal class ComputeServiceImpl(
hv.provisionedCores -= server.flavor.cpuCount
hv.availableMemory += server.flavor.memorySize
+ _attemptsError++
_schedulingAttempts.add(1, _schedulingAttemptsErrorAttr)
}
}
@@ -481,6 +510,7 @@ internal class ComputeServiceImpl(
logger.info { "[${clock.instant()}] Server ${server.uid} ${server.name} ${server.flavor} finished." }
if (activeServers.remove(server) != null) {
+ _serversActive--
_servers.add(-1, _serversActiveAttr)
}
@@ -503,7 +533,8 @@ internal class ComputeServiceImpl(
*/
private fun collectProvisionTime(result: ObservableLongMeasurement) {
for ((_, server) in servers) {
- result.record(server.lastProvisioningTimestamp, server.attributes)
+ val launchedAt = server.launchedAt ?: continue
+ result.record(launchedAt.toEpochMilli(), server.attributes)
}
}
}
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt
index f1b92c66..d2a2d896 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt
@@ -28,6 +28,7 @@ import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
import mu.KotlinLogging
import org.opendc.compute.api.*
import org.opendc.compute.service.driver.Host
+import java.time.Instant
import java.util.UUID
/**
@@ -75,7 +76,7 @@ internal class InternalServer(
/**
* The most recent timestamp when the server entered a provisioning state.
*/
- @JvmField internal var lastProvisioningTimestamp: Long = Long.MIN_VALUE
+ override var launchedAt: Instant? = null
/**
* The current scheduling request.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/telemetry/SchedulerStats.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/telemetry/SchedulerStats.kt
new file mode 100644
index 00000000..4dc70286
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/telemetry/SchedulerStats.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022 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.telemetry
+
+import org.opendc.compute.service.ComputeService
+
+/**
+ * Statistics about the scheduling component of the [ComputeService].
+ *
+ * @property hostsAvailable The number of hosts currently available for scheduling.
+ * @property hostsUnavailable The number of hosts unavailable for scheduling.
+ * @property attemptsSuccess Scheduling attempts that resulted into an allocation onto a host.
+ * @property attemptsFailure The number of failed scheduling attempt due to insufficient capacity at the moment.
+ * @property attemptsError The number of scheduling attempts that failed due to system error.
+ * @property serversPending The number of servers that are pending to be scheduled.
+ * @property serversActive The number of servers that are currently managed by the service and running.
+ */
+public data class SchedulerStats(
+ val hostsAvailable: Int,
+ val hostsUnavailable: Int,
+ val attemptsSuccess: Long,
+ val attemptsFailure: Long,
+ val attemptsError: Long,
+ val serversPending: Int,
+ val serversActive: Int
+)
diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt
index 7b8d0fe2..eb106817 100644
--- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt
+++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt
@@ -24,7 +24,6 @@ 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
@@ -48,10 +47,9 @@ import java.util.*
/**
* Test suite for the [ComputeService] interface.
*/
-@OptIn(ExperimentalCoroutinesApi::class)
internal class ComputeServiceTest {
- lateinit var scope: SimulationCoroutineScope
- lateinit var service: ComputeService
+ private lateinit var scope: SimulationCoroutineScope
+ private lateinit var service: ComputeService
@BeforeEach
fun setUp() {
@@ -128,14 +126,12 @@ internal class ComputeServiceTest {
every { host.model } returns HostModel(4 * 2600.0, 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)
@@ -150,7 +146,6 @@ internal class ComputeServiceTest {
every { host.model } returns HostModel(4 * 2600.0, 4, 2048)
every { host.state } returns HostState.DOWN
- assertEquals(0, service.hostCount)
assertEquals(emptySet<Host>(), service.hosts)
service.addHost(host)
diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt
index dfd3bc67..4e5a37ae 100644
--- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt
+++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt
@@ -23,7 +23,6 @@
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
@@ -41,7 +40,6 @@ import java.util.*
/**
* Test suite for the [InternalServer] implementation.
*/
-@OptIn(ExperimentalCoroutinesApi::class)
class InternalServerTest {
@Test
fun testEquality() {