summaryrefslogtreecommitdiff
path: root/opendc-compute/opendc-compute-service
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-11-02 17:20:00 +0100
committerFabian Mastenbroek <mail.fabianm@gmail.com>2022-11-27 20:50:13 +0000
commit4dfae28c5bd656806a7baf7855c95770f4ad0ed8 (patch)
tree52e2de58503714cc6510db614b4a654af2fdda3c /opendc-compute/opendc-compute-service
parente0856b26c3e1961e7ff4bb3ca038adc4892bbc22 (diff)
refactor(compute/service): Do not split interface and implementation
This change inlines the implementation of the compute service into the `ComputeService` interface. We do not intend to provide multiple implementations of the service. In addition, this approach makes more sense for a Java implementation.
Diffstat (limited to 'opendc-compute/opendc-compute-service')
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ComputeService.java601
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/HostView.java78
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceFlavor.java122
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceImage.java101
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceServer.java246
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/Host.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/Host.kt)88
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostListener.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostListener.kt)18
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostModel.kt)18
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostState.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostState.kt)6
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/GuestCpuStats.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestCpuStats.kt)33
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/GuestSystemStats.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/GuestSystemStats.kt)18
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/HostCpuStats.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostCpuStats.kt)39
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/HostSystemStats.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/telemetry/HostSystemStats.kt)47
-rw-r--r--opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/telemetry/SchedulerStats.java (renamed from opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/telemetry/SchedulerStats.kt)39
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt94
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt477
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/HostView.kt44
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt66
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt56
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt161
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/DifferentHostFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/RamFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/SameHostFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuFilter.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RamWeigher.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt2
-rw-r--r--opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt22
-rw-r--r--opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceFlavorTest.kt (renamed from opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalFlavorTest.kt)32
-rw-r--r--opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceImageTest.kt (renamed from opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalImageTest.kt)33
-rw-r--r--opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceServerTest.kt (renamed from opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt)121
-rw-r--r--opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt2
42 files changed, 1384 insertions, 1212 deletions
diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ComputeService.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ComputeService.java
new file mode 100644
index 00000000..eda9a79f
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ComputeService.java
@@ -0,0 +1,601 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.InstantSource;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.SplittableRandom;
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.opendc.common.Dispatcher;
+import org.opendc.common.util.Pacer;
+import org.opendc.compute.api.ComputeClient;
+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.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.ComputeScheduler;
+import org.opendc.compute.service.telemetry.SchedulerStats;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link ComputeService} hosts the API implementation of the OpenDC Compute Engine.
+ */
+public final class ComputeService implements AutoCloseable {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ComputeService.class);
+
+ /**
+ * The {@link InstantSource} representing the clock tracking the (simulation) time.
+ */
+ private final InstantSource clock;
+
+ /**
+ * The {@link ComputeScheduler} responsible for placing the servers onto hosts.
+ */
+ private final ComputeScheduler scheduler;
+
+ /**
+ * The {@link Pacer} used to pace the scheduling requests.
+ */
+ private final Pacer pacer;
+
+ /**
+ * The {@link SplittableRandom} used to generate the unique identifiers for the service resources.
+ */
+ private final SplittableRandom random = new SplittableRandom(0);
+
+ /**
+ * A flag to indicate that the service is closed.
+ */
+ private boolean isClosed;
+
+ /**
+ * A mapping from host to host view.
+ */
+ private final Map<Host, HostView> hostToView = new HashMap<>();
+
+ /**
+ * The available hypervisors.
+ */
+ private final Set<HostView> availableHosts = new HashSet<>();
+
+ /**
+ * The servers that should be launched by the service.
+ */
+ private final Deque<SchedulingRequest> queue = new ArrayDeque<>();
+
+ /**
+ * The active servers in the system.
+ */
+ private final Map<Server, Host> activeServers = new HashMap<>();
+
+ /**
+ * The registered flavors for this compute service.
+ */
+ private final Map<UUID, ServiceFlavor> flavorById = new HashMap<>();
+
+ private final List<ServiceFlavor> flavors = new ArrayList<>();
+
+ /**
+ * The registered images for this compute service.
+ */
+ private final Map<UUID, ServiceImage> imageById = new HashMap<>();
+
+ private final List<ServiceImage> images = new ArrayList<>();
+
+ /**
+ * The registered servers for this compute service.
+ */
+ private final Map<UUID, ServiceServer> serverById = new HashMap<>();
+
+ private final List<ServiceServer> servers = new ArrayList<>();
+
+ /**
+ * A [HostListener] used to track the active servers.
+ */
+ private final HostListener hostListener = new HostListener() {
+ @Override
+ public void onStateChanged(@NotNull Host host, @NotNull HostState newState) {
+ LOGGER.debug("Host {} state changed: {}", host, newState);
+
+ final HostView hv = hostToView.get(host);
+
+ if (hv != null) {
+ if (newState == HostState.UP) {
+ availableHosts.add(hv);
+ } else {
+ availableHosts.remove(hv);
+ }
+ }
+
+ // Re-schedule on the new machine
+ requestSchedulingCycle();
+ }
+
+ @Override
+ public void onStateChanged(@NotNull Host host, @NotNull Server server, @NotNull ServerState newState) {
+ final ServiceServer serviceServer = (ServiceServer) server;
+
+ if (serviceServer.getHost() != host) {
+ // This can happen when a server is rescheduled and started on another machine, while being deleted from
+ // the old machine.
+ return;
+ }
+
+ serviceServer.setState(newState);
+
+ if (newState == ServerState.TERMINATED || newState == ServerState.DELETED) {
+ LOGGER.info("Server {} {} {} finished", server.getUid(), server.getName(), server.getFlavor());
+
+ if (activeServers.remove(server) != null) {
+ serversActive--;
+ }
+
+ HostView hv = hostToView.get(host);
+ final ServiceFlavor flavor = serviceServer.getFlavor();
+ if (hv != null) {
+ hv.provisionedCores -= flavor.getCpuCount();
+ hv.instanceCount--;
+ hv.availableMemory += flavor.getMemorySize();
+ } else {
+ LOGGER.error("Unknown host {}", host);
+ }
+
+ // Try to reschedule if needed
+ requestSchedulingCycle();
+ }
+ }
+ };
+
+ private int maxCores = 0;
+ private long maxMemory = 0L;
+ private long attemptsSuccess = 0L;
+ private long attemptsFailure = 0L;
+ private long attemptsError = 0L;
+ private int serversPending = 0;
+ private int serversActive = 0;
+
+ /**
+ * Construct a {@link ComputeService} instance.
+ */
+ ComputeService(Dispatcher dispatcher, ComputeScheduler scheduler, Duration quantum) {
+ this.clock = dispatcher.getTimeSource();
+ this.scheduler = scheduler;
+ this.pacer = new Pacer(dispatcher, quantum.toMillis(), (time) -> doSchedule());
+ }
+
+ /**
+ * Create a new {@link Builder} instance.
+ */
+ public static Builder builder(Dispatcher dispatcher, ComputeScheduler scheduler) {
+ return new Builder(dispatcher, scheduler);
+ }
+
+ /**
+ * Create a new {@link ComputeClient} to control the compute service.
+ */
+ public ComputeClient newClient() {
+ if (isClosed) {
+ throw new IllegalStateException("Service is closed");
+ }
+ return new Client(this);
+ }
+
+ /**
+ * Return the {@link Server}s hosted by this service.
+ */
+ public List<Server> getServers() {
+ return Collections.unmodifiableList(servers);
+ }
+
+ /**
+ * Add a {@link Host} to the scheduling pool of the compute service.
+ */
+ public void addHost(Host host) {
+ // Check if host is already known
+ if (hostToView.containsKey(host)) {
+ return;
+ }
+
+ HostView hv = new HostView(host);
+ HostModel model = host.getModel();
+
+ maxCores = Math.max(maxCores, model.cpuCount());
+ maxMemory = Math.max(maxMemory, model.memoryCapacity());
+ hostToView.put(host, hv);
+
+ if (host.getState() == HostState.UP) {
+ availableHosts.add(hv);
+ }
+
+ scheduler.addHost(hv);
+ host.addListener(hostListener);
+ }
+
+ /**
+ * Remove a {@link Host} from the scheduling pool of the compute service.
+ */
+ public void removeHost(Host host) {
+ HostView view = hostToView.remove(host);
+ if (view != null) {
+ availableHosts.remove(view);
+ scheduler.removeHost(view);
+ host.removeListener(hostListener);
+ }
+ }
+
+ /**
+ * Lookup the {@link Host} that currently hosts the specified {@link Server}.
+ */
+ public Host lookupHost(Server server) {
+ if (server instanceof ServiceServer) {
+ return ((ServiceServer) server).getHost();
+ }
+
+ ServiceServer internal =
+ Objects.requireNonNull(serverById.get(server.getUid()), "Invalid server passed to lookupHost");
+ return internal.getHost();
+ }
+
+ /**
+ * Return the {@link Host}s that are registered with this service.
+ */
+ public Set<Host> getHosts() {
+ return Collections.unmodifiableSet(hostToView.keySet());
+ }
+
+ /**
+ * Collect the statistics about the scheduler component of this service.
+ */
+ public SchedulerStats getSchedulerStats() {
+ return new SchedulerStats(
+ availableHosts.size(),
+ hostToView.size() - availableHosts.size(),
+ attemptsSuccess,
+ attemptsFailure,
+ attemptsError,
+ servers.size(),
+ serversPending,
+ serversActive);
+ }
+
+ @Override
+ public void close() {
+ if (isClosed) {
+ return;
+ }
+
+ isClosed = true;
+ pacer.cancel();
+ }
+
+ /**
+ * Enqueue the specified [server] to be scheduled onto a host.
+ */
+ SchedulingRequest schedule(ServiceServer server) {
+ LOGGER.debug("Enqueueing server {} to be assigned to host", server.getUid());
+
+ long now = clock.millis();
+ SchedulingRequest request = new SchedulingRequest(server, now);
+
+ server.launchedAt = Instant.ofEpochMilli(now);
+ queue.add(request);
+ serversPending++;
+ requestSchedulingCycle();
+ return request;
+ }
+
+ void delete(ServiceFlavor flavor) {
+ flavorById.remove(flavor.getUid());
+ flavors.remove(flavor);
+ }
+
+ void delete(ServiceImage image) {
+ imageById.remove(image.getUid());
+ images.remove(image);
+ }
+
+ void delete(ServiceServer server) {
+ serverById.remove(server.getUid());
+ servers.remove(server);
+ }
+
+ /**
+ * Indicate that a new scheduling cycle is needed due to a change to the service's state.
+ */
+ private void requestSchedulingCycle() {
+ // Bail out in case the queue is empty.
+ if (queue.isEmpty()) {
+ return;
+ }
+
+ pacer.enqueue();
+ }
+
+ /**
+ * Run a single scheduling iteration.
+ */
+ private void doSchedule() {
+ while (!queue.isEmpty()) {
+ SchedulingRequest request = queue.peek();
+
+ if (request.isCancelled) {
+ queue.poll();
+ serversPending--;
+ continue;
+ }
+
+ final ServiceServer server = request.server;
+ final ServiceFlavor flavor = server.getFlavor();
+ final HostView hv = scheduler.select(request.server);
+
+ if (hv == null || !hv.getHost().canFit(server)) {
+ LOGGER.trace(
+ "Server {} selected for scheduling but no capacity available for it at the moment", server);
+
+ if (flavor.getMemorySize() > maxMemory || flavor.getCpuCount() > maxCores) {
+ // Remove the incoming image
+ queue.poll();
+ serversPending--;
+ attemptsFailure++;
+
+ LOGGER.warn("Failed to spawn {}: does not fit", server);
+
+ server.setState(ServerState.TERMINATED);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ Host host = hv.getHost();
+
+ // Remove request from queue
+ queue.poll();
+ serversPending--;
+
+ LOGGER.info("Assigned server {} to host {}", server, host);
+
+ try {
+ server.host = host;
+
+ host.spawn(server);
+ host.start(server);
+
+ serversActive++;
+ attemptsSuccess++;
+
+ hv.instanceCount++;
+ hv.provisionedCores += flavor.getCpuCount();
+ hv.availableMemory -= flavor.getMemorySize();
+
+ activeServers.put(server, host);
+ } catch (Exception cause) {
+ LOGGER.error("Failed to deploy VM", cause);
+ attemptsError++;
+ }
+ }
+ }
+
+ /**
+ * Builder class for a {@link ComputeService}.
+ */
+ public static class Builder {
+ private final Dispatcher dispatcher;
+ private final ComputeScheduler computeScheduler;
+ private Duration quantum = Duration.ofMinutes(5);
+
+ Builder(Dispatcher dispatcher, ComputeScheduler computeScheduler) {
+ this.dispatcher = dispatcher;
+ this.computeScheduler = computeScheduler;
+ }
+
+ /**
+ * Set the scheduling quantum of the service.
+ */
+ public Builder withQuantum(Duration quantum) {
+ this.quantum = quantum;
+ return this;
+ }
+
+ /**
+ * Build a {@link ComputeService}.
+ */
+ public ComputeService build() {
+ return new ComputeService(dispatcher, computeScheduler, quantum);
+ }
+ }
+
+ /**
+ * Implementation of {@link ComputeClient} using a {@link ComputeService}.
+ */
+ private static class Client implements ComputeClient {
+ private final ComputeService service;
+ private boolean isClosed;
+
+ Client(ComputeService service) {
+ this.service = service;
+ }
+
+ /**
+ * Method to check if the client is still open and throw an exception if it is not.
+ */
+ private void checkOpen() {
+ if (isClosed) {
+ throw new IllegalStateException("Client is already closed");
+ }
+ }
+
+ @NotNull
+ @Override
+ public List<Flavor> queryFlavors() {
+ checkOpen();
+ return new ArrayList<>(service.flavors);
+ }
+
+ @Override
+ public Flavor findFlavor(@NotNull UUID id) {
+ checkOpen();
+
+ return service.flavorById.get(id);
+ }
+
+ @NotNull
+ @Override
+ public Flavor newFlavor(
+ @NotNull String name,
+ int cpuCount,
+ long memorySize,
+ @NotNull Map<String, String> labels,
+ @NotNull Map<String, ?> meta) {
+ checkOpen();
+
+ final ComputeService service = this.service;
+ UUID uid = new UUID(service.clock.millis(), service.random.nextLong());
+ ServiceFlavor flavor = new ServiceFlavor(service, uid, name, cpuCount, memorySize, labels, meta);
+
+ service.flavorById.put(uid, flavor);
+ service.flavors.add(flavor);
+
+ return flavor;
+ }
+
+ @NotNull
+ @Override
+ public List<Image> queryImages() {
+ checkOpen();
+
+ return new ArrayList<>(service.images);
+ }
+
+ @Override
+ public Image findImage(@NotNull UUID id) {
+ checkOpen();
+
+ return service.imageById.get(id);
+ }
+
+ @NotNull
+ public Image newImage(@NotNull String name, @NotNull Map<String, String> labels, @NotNull Map<String, ?> meta) {
+ checkOpen();
+
+ final ComputeService service = this.service;
+ UUID uid = new UUID(service.clock.millis(), service.random.nextLong());
+
+ ServiceImage image = new ServiceImage(service, uid, name, labels, meta);
+
+ service.imageById.put(uid, image);
+ service.images.add(image);
+
+ return image;
+ }
+
+ @NotNull
+ @Override
+ public Server newServer(
+ @NotNull String name,
+ @NotNull Image image,
+ @NotNull Flavor flavor,
+ @NotNull Map<String, String> labels,
+ @NotNull Map<String, ?> meta,
+ boolean start) {
+ checkOpen();
+
+ final ComputeService service = this.service;
+ UUID uid = new UUID(service.clock.millis(), service.random.nextLong());
+
+ final ServiceFlavor internalFlavor =
+ Objects.requireNonNull(service.flavorById.get(flavor.getUid()), "Unknown flavor");
+ final ServiceImage internalImage =
+ Objects.requireNonNull(service.imageById.get(image.getUid()), "Unknown image");
+
+ ServiceServer server = new ServiceServer(service, uid, name, internalFlavor, internalImage, labels, meta);
+
+ service.serverById.put(uid, server);
+ service.servers.add(server);
+
+ if (start) {
+ server.start();
+ }
+
+ return server;
+ }
+
+ @Nullable
+ @Override
+ public Server findServer(@NotNull UUID id) {
+ checkOpen();
+ return service.serverById.get(id);
+ }
+
+ @NotNull
+ @Override
+ public List<Server> queryServers() {
+ checkOpen();
+
+ return new ArrayList<>(service.servers);
+ }
+
+ @Override
+ public void close() {
+ isClosed = true;
+ }
+
+ @Override
+ public String toString() {
+ return "ComputeService.Client";
+ }
+ }
+
+ /**
+ * A request to schedule a {@link ServiceServer} onto one of the {@link Host}s.
+ */
+ static class SchedulingRequest {
+ final ServiceServer server;
+ final long submitTime;
+
+ boolean isCancelled;
+
+ SchedulingRequest(ServiceServer server, long submitTime) {
+ this.server = server;
+ this.submitTime = submitTime;
+ }
+ }
+}
diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/HostView.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/HostView.java
new file mode 100644
index 00000000..6e2cdcb4
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/HostView.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import org.opendc.compute.service.driver.Host;
+
+/**
+ * A view of a {@link Host} as seen from the {@link ComputeService}.
+ */
+public class HostView {
+ private final Host host;
+ int instanceCount;
+ long availableMemory;
+ int provisionedCores;
+
+ /**
+ * Construct a {@link HostView} instance.
+ *
+ * @param host The host to create a view of.
+ */
+ public HostView(Host host) {
+ this.host = host;
+ this.availableMemory = host.getModel().memoryCapacity();
+ }
+
+ /**
+ * The {@link Host} this is a view of.
+ */
+ public Host getHost() {
+ return host;
+ }
+
+ /**
+ * Return the number of instances on this host.
+ */
+ public int getInstanceCount() {
+ return instanceCount;
+ }
+
+ /**
+ * Return the available memory of the host.
+ */
+ public long getAvailableMemory() {
+ return availableMemory;
+ }
+
+ /**
+ * Return the provisioned cores on the host.
+ */
+ public int getProvisionedCores() {
+ return provisionedCores;
+ }
+
+ @Override
+ public String toString() {
+ return "HostView[host=" + host + "]";
+ }
+}
diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceFlavor.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceFlavor.java
new file mode 100644
index 00000000..dba87e2c
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceFlavor.java
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+import org.opendc.compute.api.Flavor;
+
+/**
+ * Implementation of {@link Flavor} provided by {@link ComputeService}.
+ */
+public final class ServiceFlavor implements Flavor {
+ private final ComputeService service;
+ private final UUID uid;
+ private final String name;
+ private final int cpuCount;
+ private final long memorySize;
+ private final Map<String, String> labels;
+ private final Map<String, ?> meta;
+
+ ServiceFlavor(
+ ComputeService service,
+ UUID uid,
+ String name,
+ int cpuCount,
+ long memorySize,
+ Map<String, String> labels,
+ Map<String, ?> meta) {
+ this.service = service;
+ this.uid = uid;
+ this.name = name;
+ this.cpuCount = cpuCount;
+ this.memorySize = memorySize;
+ this.labels = labels;
+ this.meta = meta;
+ }
+
+ @Override
+ public int getCpuCount() {
+ return cpuCount;
+ }
+
+ @Override
+ public long getMemorySize() {
+ return memorySize;
+ }
+
+ @NotNull
+ @Override
+ public UUID getUid() {
+ return uid;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @NotNull
+ @Override
+ public Map<String, String> getLabels() {
+ return Collections.unmodifiableMap(labels);
+ }
+
+ @NotNull
+ @Override
+ public Map<String, Object> getMeta() {
+ return Collections.unmodifiableMap(meta);
+ }
+
+ @Override
+ public void reload() {
+ // No-op: this object is the source-of-truth
+ }
+
+ @Override
+ public void delete() {
+ service.delete(this);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ServiceFlavor flavor = (ServiceFlavor) o;
+ return service.equals(flavor.service) && uid.equals(flavor.uid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(service, uid);
+ }
+
+ @Override
+ public String toString() {
+ return "Flavor[uid=" + uid + ",name=" + name + "]";
+ }
+}
diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceImage.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceImage.java
new file mode 100644
index 00000000..706be483
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceImage.java
@@ -0,0 +1,101 @@
+/*
+ * 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;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+import org.opendc.compute.api.Image;
+
+/**
+ * Implementation of {@link Image} provided by {@link ComputeService}.
+ */
+public final class ServiceImage implements Image {
+ private final ComputeService service;
+ private final UUID uid;
+ private final String name;
+ private final Map<String, String> labels;
+ private final Map<String, ?> meta;
+
+ ServiceImage(ComputeService service, UUID uid, String name, Map<String, String> labels, Map<String, ?> meta) {
+ this.service = service;
+ this.uid = uid;
+ this.name = name;
+ this.labels = labels;
+ this.meta = meta;
+ }
+
+ @NotNull
+ @Override
+ public UUID getUid() {
+ return uid;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @NotNull
+ @Override
+ public Map<String, String> getLabels() {
+ return Collections.unmodifiableMap(labels);
+ }
+
+ @NotNull
+ @Override
+ public Map<String, Object> getMeta() {
+ return Collections.unmodifiableMap(meta);
+ }
+
+ @Override
+ public void reload() {
+ // No-op: this object is the source-of-truth
+ }
+
+ @Override
+ public void delete() {
+ service.delete(this);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ServiceImage image = (ServiceImage) o;
+ return service.equals(image.service) && uid.equals(image.uid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(service, uid);
+ }
+
+ @Override
+ public String toString() {
+ return "Image[uid=" + uid + ",name=" + name + "]";
+ }
+}
diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceServer.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceServer.java
new file mode 100644
index 00000000..265feac0
--- /dev/null
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceServer.java
@@ -0,0 +1,246 @@
+/*
+ * 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;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of {@link Server} provided by {@link ComputeService}.
+ */
+public final class ServiceServer implements Server {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ServiceServer.class);
+
+ private final ComputeService service;
+ private final UUID uid;
+ private final String name;
+ private final ServiceFlavor flavor;
+ private final ServiceImage image;
+ private final Map<String, String> labels;
+ private final Map<String, ?> meta;
+
+ private final List<ServerWatcher> watchers = new ArrayList<>();
+ private ServerState state = ServerState.TERMINATED;
+ Instant launchedAt = null;
+ Host host = null;
+ private ComputeService.SchedulingRequest request = null;
+
+ ServiceServer(
+ ComputeService service,
+ UUID uid,
+ String name,
+ ServiceFlavor flavor,
+ ServiceImage image,
+ Map<String, String> labels,
+ Map<String, ?> meta) {
+ this.service = service;
+ this.uid = uid;
+ this.name = name;
+ this.flavor = flavor;
+ this.image = image;
+ this.labels = labels;
+ this.meta = meta;
+ }
+
+ @NotNull
+ @Override
+ public UUID getUid() {
+ return uid;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @NotNull
+ @Override
+ public ServiceFlavor getFlavor() {
+ return flavor;
+ }
+
+ @NotNull
+ @Override
+ public ServiceImage getImage() {
+ return image;
+ }
+
+ @NotNull
+ @Override
+ public Map<String, String> getLabels() {
+ return Collections.unmodifiableMap(labels);
+ }
+
+ @NotNull
+ @Override
+ public Map<String, Object> getMeta() {
+ return Collections.unmodifiableMap(meta);
+ }
+
+ @NotNull
+ @Override
+ public ServerState getState() {
+ return state;
+ }
+
+ @Nullable
+ @Override
+ public Instant getLaunchedAt() {
+ return launchedAt;
+ }
+
+ /**
+ * Return the {@link Host} on which the server is running or <code>null</code> if it is not running on a host.
+ */
+ public Host getHost() {
+ return host;
+ }
+
+ @Override
+ public void start() {
+ switch (state) {
+ case PROVISIONING:
+ LOGGER.debug("User tried to start server but request is already pending: doing nothing");
+ case RUNNING:
+ LOGGER.debug("User tried to start server but server is already running");
+ break;
+ case DELETED:
+ LOGGER.warn("User tried to start deleted server");
+ throw new IllegalStateException("Server is deleted");
+ default:
+ LOGGER.info("User requested to start server {}", uid);
+ setState(ServerState.PROVISIONING);
+ assert request == null : "Scheduling request already active";
+ request = service.schedule(this);
+ break;
+ }
+ }
+
+ @Override
+ public void stop() {
+ switch (state) {
+ case PROVISIONING:
+ cancelProvisioningRequest();
+ setState(ServerState.TERMINATED);
+ break;
+ case RUNNING:
+ case ERROR:
+ final Host host = this.host;
+ if (host == null) {
+ throw new IllegalStateException("Server not running");
+ }
+ host.stop(this);
+ break;
+ }
+ }
+
+ @Override
+ public void watch(@NotNull ServerWatcher watcher) {
+ watchers.add(watcher);
+ }
+
+ @Override
+ public void unwatch(@NotNull ServerWatcher watcher) {
+ watchers.remove(watcher);
+ }
+
+ @Override
+ public void reload() {
+ // No-op: this object is the source-of-truth
+ }
+
+ @Override
+ public void delete() {
+ switch (state) {
+ case PROVISIONING:
+ case TERMINATED:
+ cancelProvisioningRequest();
+ service.delete(this);
+ setState(ServerState.DELETED);
+ break;
+ case RUNNING:
+ case ERROR:
+ final Host host = this.host;
+ if (host == null) {
+ throw new IllegalStateException("Server not running");
+ }
+ host.delete(this);
+ service.delete(this);
+ setState(ServerState.DELETED);
+ break;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ServiceServer server = (ServiceServer) o;
+ return service.equals(server.service) && uid.equals(server.uid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(service, uid);
+ }
+
+ @Override
+ public String toString() {
+ return "Server[uid=" + uid + ",name=" + name + ",state=" + state + "]";
+ }
+
+ void setState(ServerState state) {
+ if (this.state != state) {
+ for (ServerWatcher watcher : watchers) {
+ watcher.onStateChanged(this, state);
+ }
+ }
+
+ this.state = state;
+ }
+
+ /**
+ * Cancel the provisioning request if active.
+ */
+ private void cancelProvisioningRequest() {
+ final ComputeService.SchedulingRequest request = this.request;
+ if (request != null) {
+ this.request = null;
+ request.isCancelled = true;
+ }
+ }
+}
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/java/org/opendc/compute/service/driver/Host.java
index efcc0f2c..760d7f1a 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/java/org/opendc/compute/service/driver/Host.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,116 +20,118 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver
+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.UUID
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+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;
/**
- * Base interface for representing compute resources that host virtualized [Server] instances.
+ * Base interface for representing compute resources that host virtualized {@link Server} instances.
*/
public interface Host {
/**
- * A unique identifier representing the host.
+ * Return a unique identifier representing the host.
*/
- public val uid: UUID
+ UUID getUid();
/**
- * The name of this host.
+ * Return the name of this host.
*/
- public val name: String
+ String getName();
/**
- * The machine model of the host.
+ * Return the machine model of the host.
*/
- public val model: HostModel
+ HostModel getModel();
/**
- * The state of the host.
+ * Return the state of the host.
*/
- public val state: HostState
+ HostState getState();
/**
- * Meta-data associated with the host.
+ * Return the meta-data associated with the host.
*/
- public val meta: Map<String, Any>
+ Map<String, ?> getMeta();
/**
- * The [Server] instances known to the host.
+ * Return the {@link Server} instances known to the host.
*/
- public val instances: Set<Server>
+ Set<Server> getInstances();
/**
- * Determine whether the specified [instance][server] can still fit on this host.
+ * Determine whether the specified <code>server</code> can still fit on this host.
*/
- public fun canFit(server: Server): Boolean
+ boolean canFit(Server server);
/**
- * Register the specified [instance][server] on the host.
+ * Register the specified <code>server</code> on the host.
*/
- public fun spawn(server: Server)
+ void spawn(Server server);
/**
- * Determine whether the specified [instance][server] exists on the host.
+ * Determine whether the specified <code>server</code> exists on the host.
*/
- public operator fun contains(server: Server): Boolean
+ boolean contains(Server server);
/**
- * Start the server [instance][server] if it is currently not running on this host.
+ * Start the server if it is currently not running on this host.
*
* @throws IllegalArgumentException if the server is not present on the host.
*/
- public fun start(server: Server)
+ void start(Server server);
/**
- * Stop the server [instance][server] if it is currently running on this host.
+ * Stop the server if it is currently running on this host.
*
* @throws IllegalArgumentException if the server is not present on the host.
*/
- public fun stop(server: Server)
+ void stop(Server server);
/**
- * Delete the specified [instance][server] on this host and cleanup all resources associated with it.
+ * Delete the specified <code>server</code> on this host and cleanup all resources associated with it.
*/
- public fun delete(server: Server)
+ void delete(Server server);
/**
* Add a [HostListener] to this host.
*/
- public fun addListener(listener: HostListener)
+ void addListener(HostListener listener);
/**
* Remove a [HostListener] from this host.
*/
- public fun removeListener(listener: HostListener)
+ void removeListener(HostListener listener);
/**
* Query the system statistics of the host.
*/
- public fun getSystemStats(): HostSystemStats
+ HostSystemStats getSystemStats();
/**
- * Query the system statistics of a [Server] that is located on this host.
+ * Query the system statistics of a {@link Server} that is located on this host.
*
- * @param server The [Server] to obtain the system statistics of.
+ * @param server The {@link Server} to obtain the system statistics of.
* @throws IllegalArgumentException if the server is not present on the host.
*/
- public fun getSystemStats(server: Server): GuestSystemStats
+ GuestSystemStats getSystemStats(Server server);
/**
* Query the CPU statistics of the host.
*/
- public fun getCpuStats(): HostCpuStats
+ HostCpuStats getCpuStats();
/**
- * Query the CPU statistics of a [Server] that is located on this host.
+ * Query the CPU statistics of a {@link Server} that is located on this host.
*
- * @param server The [Server] to obtain the CPU statistics of.
+ * @param server The {@link Server} to obtain the CPU statistics of.
* @throws IllegalArgumentException if the server is not present on the host.
*/
- public fun getCpuStats(server: Server): GuestCpuStats
+ GuestCpuStats getCpuStats(Server server);
}
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostListener.kt b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostListener.java
index f076cae3..feefca40 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostListener.kt
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,22 +20,22 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver
+package org.opendc.compute.service.driver;
-import org.opendc.compute.api.Server
-import org.opendc.compute.api.ServerState
+import org.opendc.compute.api.Server;
+import org.opendc.compute.api.ServerState;
/**
- * Listener interface for events originating from a [Host].
+ * Listener interface for events originating from a {@link Host}.
*/
public interface HostListener {
/**
- * This method is invoked when the state of an [instance][server] on [host] changes.
+ * This method is invoked when the state of <code>server</code> on <code>host</code> changes.
*/
- public fun onStateChanged(host: Host, server: Server, newState: ServerState) {}
+ default void onStateChanged(Host host, Server server, ServerState newState) {}
/**
- * This method is invoked when the state of a [Host] has changed.
+ * This method is invoked when the state of a {@link Host} has changed.
*/
- public fun onStateChanged(host: Host, newState: HostState) {}
+ default void onStateChanged(Host host, HostState newState) {}
}
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostModel.kt b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java
index f3b94e3d..9caa6da7 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostModel.kt
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,17 +20,13 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver
+package org.opendc.compute.service.driver;
/**
- * Describes the static machine properties of the host.
+ * Record describing the static machine properties of the host.
*
- * @property cpuCapacity The total CPU capacity of the host in MHz.
- * @property cpuCount The number of logical processing cores available for this host.
- * @property memoryCapacity The amount of memory available for this host in MB.
+ * @param cpuCapacity The total CPU capacity of the host in MHz.
+ * @param cpuCount The number of logical processing cores available for this host.
+ * @param memoryCapacity The amount of memory available for this host in MB.
*/
-public data class HostModel(
- public val cpuCapacity: Double,
- public val cpuCount: Int,
- public val memoryCapacity: Long
-)
+public record HostModel(double cpuCapacity, int cpuCount, long memoryCapacity) {}
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostState.kt b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostState.java
index 544b6530..ce12a67e 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/driver/HostState.kt
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostState.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,12 +20,12 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver
+package org.opendc.compute.service.driver;
/**
* The state of a host.
*/
-public enum class HostState {
+public enum HostState {
/**
* The host is up and able to host guests.
*/
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/java/org/opendc/compute/service/driver/telemetry/GuestCpuStats.java
index b5d63471..0b78c7ea 100644
--- 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/java/org/opendc/compute/service/driver/telemetry/GuestCpuStats.java
@@ -20,25 +20,24 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver.telemetry
+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.
+ * @param activeTime The cumulative time (in seconds) that the CPUs of the guest were actively running.
+ * @param idleTime The cumulative time (in seconds) the CPUs of the guest were idle.
+ * @param stealTime The cumulative CPU time (in seconds) that the guest was ready to run, but not granted time by the host.
+ * @param lostTime The cumulative CPU time (in seconds) that was lost due to interference with other machines.
+ * @param capacity The available CPU capacity of the guest (in MHz).
+ * @param usage Amount of CPU resources (in MHz) actually used by the guest.
+ * @param utilization The 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
-)
+public record GuestCpuStats(
+ long activeTime,
+ long idleTime,
+ long stealTime,
+ long lostTime,
+ double capacity,
+ double usage,
+ double utilization) {}
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/java/org/opendc/compute/service/driver/telemetry/GuestSystemStats.java
index 6fec5175..dbf98dd5 100644
--- 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/java/org/opendc/compute/service/driver/telemetry/GuestSystemStats.java
@@ -20,20 +20,16 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver.telemetry
+package org.opendc.compute.service.driver.telemetry;
-import java.time.Duration
-import java.time.Instant
+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.
+ * @param uptime The cumulative uptime of the guest since last boot (in ms).
+ * @param downtime The cumulative downtime of the guest since last boot (in ms).
+ * @param bootTime The time at which the guest booted.
*/
-public data class GuestSystemStats(
- val uptime: Duration,
- val downtime: Duration,
- val bootTime: Instant?
-)
+public record GuestSystemStats(Duration uptime, Duration downtime, Instant bootTime) {}
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/java/org/opendc/compute/service/driver/telemetry/HostCpuStats.java
index 55e23c0e..d1c2328b 100644
--- 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/java/org/opendc/compute/service/driver/telemetry/HostCpuStats.java
@@ -20,28 +20,27 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver.telemetry
+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.
+ * @param activeTime The cumulative time (in seconds) that the CPUs of the host were actively running.
+ * @param idleTime The cumulative time (in seconds) the CPUs of the host were idle.
+ * @param stealTime The cumulative CPU time (in seconds) that virtual machines were ready to run, but were not able to.
+ * @param lostTime The cumulative CPU time (in seconds) that was lost due to interference between virtual machines.
+ * @param capacity The available CPU capacity of the host (in MHz).
+ * @param demand Amount of CPU resources (in MHz) the guests would use if there were no CPU contention or CPU
+ * limits.
+ * @param usage Amount of CPU resources (in MHz) actually used by the host.
+ * @param utilization The 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
-)
+public record HostCpuStats(
+ long activeTime,
+ long idleTime,
+ long stealTime,
+ long lostTime,
+ double capacity,
+ double demand,
+ double usage,
+ double utilization) {}
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/java/org/opendc/compute/service/driver/telemetry/HostSystemStats.java
index 56bd017d..c0928f1b 100644
--- 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/java/org/opendc/compute/service/driver/telemetry/HostSystemStats.java
@@ -20,32 +20,31 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.driver.telemetry
+package org.opendc.compute.service.driver.telemetry;
-import java.time.Duration
-import java.time.Instant
+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.
+ *
+ * @param uptime The cumulative uptime of the host since last boot (in ms).
+ * @param downtime The cumulative downtime of the host since last boot (in ms).
+ * @param bootTime The time at which the server started.
+ * @param powerUsage Instantaneous power usage of the system (in W).
+ * @param energyUsage The cumulative energy usage of the system (in J).
+ * @param guestsTerminated The number of guests that are in a terminated state.
+ * @param guestsRunning The number of guests that are in a running state.
+ * @param guestsError The number of guests that are in an error state.
+ * @param 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
-)
+public record HostSystemStats(
+ Duration uptime,
+ Duration downtime,
+ Instant bootTime,
+ double powerUsage,
+ double energyUsage,
+ int guestsTerminated,
+ int guestsRunning,
+ int guestsError,
+ int guestsInvalid) {}
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/java/org/opendc/compute/service/telemetry/SchedulerStats.java
index 6e9f458a..2157169b 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/telemetry/SchedulerStats.kt
+++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/telemetry/SchedulerStats.java
@@ -20,29 +20,26 @@
* SOFTWARE.
*/
-package org.opendc.compute.service.telemetry
-
-import org.opendc.compute.service.ComputeService
+package org.opendc.compute.service.telemetry;
/**
* 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 serversTotal The number of servers registered with the service.
- * @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.
+ * @param hostsAvailable The number of hosts currently available for scheduling.
+ * @param hostsUnavailable The number of hosts unavailable for scheduling.
+ * @param attemptsSuccess Scheduling attempts that resulted into an allocation onto a host.
+ * @param attemptsFailure The number of failed scheduling attempt due to insufficient capacity at the moment.
+ * @param attemptsError The number of scheduling attempts that failed due to system error.
+ * @param serversTotal The number of servers registered with the service.
+ * @param serversPending The number of servers that are pending to be scheduled.
+ * @param 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 serversTotal: Int,
- val serversPending: Int,
- val serversActive: Int
-)
+public record SchedulerStats(
+ int hostsAvailable,
+ int hostsUnavailable,
+ long attemptsSuccess,
+ long attemptsFailure,
+ long attemptsError,
+ int serversTotal,
+ int serversPending,
+ int serversActive) {}
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
deleted file mode 100644
index 9d7dcba6..00000000
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/ComputeService.kt
+++ /dev/null
@@ -1,94 +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 org.opendc.common.Dispatcher
-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.Duration
-
-/**
- * The [ComputeService] hosts the API implementation of the OpenDC Compute service.
- */
-public interface ComputeService : AutoCloseable {
- /**
- * The servers that are registered with the "compute" service.
- */
- public val servers: List<Server>
-
- /**
- * The hosts that are registered with the "compute" service.
- */
- public val hosts: Set<Host>
-
- /**
- * 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()
-
- /**
- * 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.
- *
- * @param dispatcher The [Dispatcher] for scheduling future events.
- * @param scheduler The scheduler implementation to use.
- * @param schedulingQuantum The interval between scheduling cycles.
- */
- public operator fun invoke(
- dispatcher: Dispatcher,
- scheduler: ComputeScheduler,
- schedulingQuantum: Duration = Duration.ofMinutes(5)
- ): ComputeService {
- return ComputeServiceImpl(dispatcher, scheduler, schedulingQuantum)
- }
- }
-}
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
deleted file mode 100644
index ac66ff8b..00000000
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt
+++ /dev/null
@@ -1,477 +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.common.Dispatcher
-import org.opendc.common.util.Pacer
-import org.opendc.compute.api.ComputeClient
-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.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.compute.service.telemetry.SchedulerStats
-import java.time.Duration
-import java.time.Instant
-import java.util.ArrayDeque
-import java.util.Deque
-import java.util.Random
-import java.util.UUID
-import kotlin.math.max
-
-/**
- * Internal implementation of the OpenDC Compute service.
- *
- * @param dispatcher The [Dispatcher] for scheduling future events.
- * @param scheduler The scheduler implementation to use.
- * @param schedulingQuantum The interval between scheduling cycles.
- */
-internal class ComputeServiceImpl(
- private val dispatcher: Dispatcher,
- private val scheduler: ComputeScheduler,
- schedulingQuantum: Duration
-) : ComputeService, HostListener {
- /**
- * 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 flavorById = mutableMapOf<UUID, InternalFlavor>()
- private val flavors: MutableList<Flavor> = mutableListOf()
-
- /**
- * The registered images for this compute service.
- */
- internal val imageById = mutableMapOf<UUID, InternalImage>()
- private val images: MutableList<Image> = mutableListOf()
-
- /**
- * The registered servers for this compute service.
- */
- private val serverById = mutableMapOf<UUID, InternalServer>()
- override val servers: MutableList<Server> = mutableListOf()
-
- override val hosts: Set<Host>
- get() = hostToView.keys
-
- private val clock = dispatcher.timeSource
- private var maxCores = 0
- private var maxMemory = 0L
- private var _attemptsSuccess = 0L
- private var _attemptsFailure = 0L
- private var _attemptsError = 0L
- private var _serversPending = 0
- private var _serversActive = 0
- private var isClosed = false
-
- /**
- * The [Pacer] to use for scheduling the scheduler cycles.
- */
- private val pacer = Pacer(dispatcher, schedulingQuantum.toMillis()) { doSchedule() }
-
- override fun newClient(): ComputeClient {
- check(!isClosed) { "Service is already closed" }
- return Client(this)
- }
-
- 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.memoryCapacity)
- hostToView[host] = hv
-
- if (host.state == HostState.UP) {
- availableHosts += hv
- }
-
- scheduler.addHost(hv)
- host.addListener(this)
- }
-
- override fun removeHost(host: Host) {
- val view = hostToView.remove(host)
- if (view != null) {
- availableHosts.remove(view)
- scheduler.removeHost(view)
- host.removeListener(this)
- }
- }
-
- override fun lookupHost(server: Server): Host? {
- if (server is InternalServer) {
- return server.host
- }
-
- val internal = requireNotNull(serverById[server.uid]) { "Invalid server passed to lookupHost" }
- return internal.host
- }
-
- override fun close() {
- if (isClosed) {
- return
- }
-
- isClosed = true
- pacer.cancel()
- }
-
- override fun getSchedulerStats(): SchedulerStats {
- return SchedulerStats(
- availableHosts.size,
- hostToView.size - availableHosts.size,
- _attemptsSuccess,
- _attemptsFailure,
- _attemptsError,
- servers.size,
- _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.launchedAt = Instant.ofEpochMilli(now)
- queue.add(request)
- _serversPending++
- requestSchedulingCycle()
- return request
- }
-
- internal fun delete(flavor: InternalFlavor) {
- flavorById.remove(flavor.uid)
- flavors.remove(flavor)
- }
-
- internal fun delete(image: InternalImage) {
- imageById.remove(image.uid)
- images.remove(image)
- }
-
- internal fun delete(server: InternalServer) {
- serverById.remove(server.uid)
- servers.remove(server)
- }
-
- /**
- * Indicate that a new scheduling cycle is needed due to a change to the service's state.
- */
- private fun requestSchedulingCycle() {
- // Bail out in case the queue is empty.
- if (queue.isEmpty()) {
- return
- }
-
- pacer.enqueue()
- }
-
- /**
- * Run a single scheduling iteration.
- */
- private fun doSchedule() {
- while (queue.isNotEmpty()) {
- val request = queue.peek()
-
- if (request.isCancelled) {
- queue.poll()
- _serversPending--
- 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()
- _serversPending--
- _attemptsFailure++
-
- logger.warn { "Failed to spawn $server: does not fit [${clock.instant()}]" }
-
- server.state = ServerState.TERMINATED
- continue
- } else {
- break
- }
- }
-
- val host = hv.host
-
- // Remove request from queue
- queue.poll()
- _serversPending--
-
- logger.info { "Assigned server $server to host $host." }
-
- try {
- server.host = host
-
- host.spawn(server)
- host.start(server)
-
- _serversActive++
- _attemptsSuccess++
-
- hv.instanceCount++
- hv.provisionedCores += server.flavor.cpuCount
- hv.availableMemory -= server.flavor.memorySize
-
- activeServers[server] = host
- } catch (e: Throwable) {
- logger.error(e) { "Failed to deploy VM" }
- _attemptsError++
- }
- }
- }
-
- /**
- * A request to schedule an [InternalServer] onto one of the [Host]s.
- */
- internal data class SchedulingRequest(val server: InternalServer, val submitTime: Long) {
- /**
- * 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.instant()}] Host ${host.uid} state changed: $newState" }
-
- val hv = hostToView[host]
- if (hv != null) {
- // Corner case for when the hypervisor already exists
- availableHosts += hv
- }
-
- // Re-schedule on the new machine
- requestSchedulingCycle()
- }
- else -> {
- logger.debug { "[${clock.instant()}] Host ${host.uid} state changed: $newState" }
-
- val hv = hostToView[host] ?: return
- availableHosts -= hv
-
- 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.TERMINATED || newState == ServerState.DELETED) {
- logger.info { "[${clock.instant()}] Server ${server.uid} ${server.name} ${server.flavor} finished." }
-
- if (activeServers.remove(server) != null) {
- _serversActive--
- }
-
- 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()
- }
- }
-
- /**
- * Implementation of [ComputeClient] using a [ComputeService].
- */
- private class Client(private val service: ComputeServiceImpl) : ComputeClient {
- private var isClosed: Boolean = false
-
- override fun queryFlavors(): List<Flavor> {
- check(!isClosed) { "Client is already closed" }
-
- return service.flavors.toList()
- }
-
- override fun findFlavor(id: UUID): Flavor? {
- check(!isClosed) { "Client is already closed" }
-
- return service.flavorById[id]
- }
-
- override fun newFlavor(
- name: String,
- cpuCount: Int,
- memorySize: Long,
- labels: Map<String, String>,
- meta: Map<String, Any>
- ): Flavor {
- check(!isClosed) { "Client is already closed" }
-
- val service = service
- val uid = UUID(service.clock.millis(), service.random.nextLong())
- val flavor = InternalFlavor(
- service,
- uid,
- name,
- cpuCount,
- memorySize,
- labels,
- meta
- )
-
- service.flavorById[uid] = flavor
- service.flavors.add(flavor)
-
- return flavor
- }
-
- override fun queryImages(): List<Image> {
- check(!isClosed) { "Client is already closed" }
-
- return service.images.toList()
- }
-
- override fun findImage(id: UUID): Image? {
- check(!isClosed) { "Client is already closed" }
-
- return service.imageById[id]
- }
-
- override fun newImage(name: String, labels: Map<String, String>, meta: Map<String, Any>): Image {
- check(!isClosed) { "Client is already closed" }
-
- val service = service
- val uid = UUID(service.clock.millis(), service.random.nextLong())
- val image = InternalImage(service, uid, name, labels, meta)
-
- service.imageById[uid] = image
- service.images.add(image)
-
- return image
- }
-
- override fun newServer(
- name: String,
- image: Image,
- flavor: Flavor,
- labels: Map<String, String>,
- meta: Map<String, Any>,
- start: Boolean
- ): Server {
- check(!isClosed) { "Client is closed" }
-
- val service = service
- val uid = UUID(service.clock.millis(), service.random.nextLong())
- val server = InternalServer(
- service,
- uid,
- name,
- requireNotNull(service.flavorById[flavor.uid]) { "Unknown flavor" },
- requireNotNull(service.imageById[image.uid]) { "Unknown image" },
- labels.toMutableMap(),
- meta.toMutableMap()
- )
-
- service.serverById[uid] = server
- service.servers.add(server)
-
- if (start) {
- server.start()
- }
-
- return server
- }
-
- override fun findServer(id: UUID): Server? {
- check(!isClosed) { "Client is already closed" }
-
- return service.serverById[id]
- }
-
- override fun queryServers(): List<Server> {
- check(!isClosed) { "Client is already closed" }
-
- return service.servers.toList()
- }
-
- override fun close() {
- isClosed = true
- }
-
- override fun toString(): String = "ComputeService.Client"
- }
-}
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/HostView.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/HostView.kt
deleted file mode 100644
index 0876209a..00000000
--- a/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.memoryCapacity
- public var provisionedCores: Int = 0
-
- override fun toString(): String = "HostView[host=$host]"
-}
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt
deleted file mode 100644
index 077ec865..00000000
--- a/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.UUID
-
-/**
- * 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 fun reload() {
- // No-op: this object is the source-of-truth
- }
-
- override 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/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt
deleted file mode 100644
index b27ef33a..00000000
--- a/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.UUID
-
-/**
- * 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 fun reload() {
- // No-op: this object is the source-of-truth
- }
-
- override 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/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
deleted file mode 100644
index c1353ba1..00000000
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt
+++ /dev/null
@@ -1,161 +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.Server
-import org.opendc.compute.api.ServerState
-import org.opendc.compute.api.ServerWatcher
-import org.opendc.compute.service.driver.Host
-import java.time.Instant
-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.
- */
- @JvmField internal var host: Host? = null
-
- /**
- * The most recent timestamp when the server entered a provisioning state.
- */
- override var launchedAt: Instant? = null
-
- /**
- * The current scheduling request.
- */
- private var request: ComputeServiceImpl.SchedulingRequest? = null
-
- override 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 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 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 fun reload() {
- // 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/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt
index a2ab3a2e..0ccaf991 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt
@@ -24,7 +24,7 @@ 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
+import org.opendc.compute.service.HostView
/**
* A generic scheduler interface used by the [ComputeService] to select hosts to place [Server]s on.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt
index 0840ba7e..18a319e9 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt
@@ -23,7 +23,7 @@
package org.opendc.compute.service.scheduler
import org.opendc.compute.api.Server
-import org.opendc.compute.service.internal.HostView
+import org.opendc.compute.service.HostView
import org.opendc.compute.service.scheduler.filters.HostFilter
import org.opendc.compute.service.scheduler.weights.HostWeigher
import java.util.SplittableRandom
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt
index 284c1f91..4339b3de 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt
@@ -24,7 +24,7 @@ package org.opendc.compute.service.scheduler
import mu.KotlinLogging
import org.opendc.compute.api.Server
-import org.opendc.compute.service.internal.HostView
+import org.opendc.compute.service.HostView
/**
* Policy replaying VM-cluster assignment.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt
index fb842415..b562f838 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt
@@ -23,8 +23,8 @@
package org.opendc.compute.service.scheduler.filters
import org.opendc.compute.api.Server
+import org.opendc.compute.service.HostView
import org.opendc.compute.service.driver.HostState
-import org.opendc.compute.service.internal.HostView
/**
* A [HostFilter] that filters on active hosts.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/DifferentHostFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/DifferentHostFilter.kt
index f6736ac0..4a9f41c5 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/DifferentHostFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/DifferentHostFilter.kt
@@ -23,7 +23,7 @@
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.HostView
import java.util.UUID
/**
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt
index 9e909ca6..78010fee 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt
@@ -23,7 +23,7 @@
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.HostView
import org.opendc.compute.service.scheduler.FilterScheduler
/**
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt
index ed6674b1..5aa38a88 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostFilter] that filters hosts based on the number of instances on the host.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/RamFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/RamFilter.kt
index 8a7a646c..275e8f1c 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/RamFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/RamFilter.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostFilter] that filters hosts based on the memory requirements of a [Server] and the RAM available on the host.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/SameHostFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/SameHostFilter.kt
index 090e1437..c3753866 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/SameHostFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/SameHostFilter.kt
@@ -23,7 +23,7 @@
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.HostView
import java.util.UUID
/**
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt
index 791710c8..d4dff76b 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostFilter] that filters hosts based on the vCPU speed requirements of a [Server] and the available
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuFilter.kt
index abdd79f1..448a6189 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuFilter.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuFilter.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostFilter] that filters hosts based on the vCPU requirements of a [Server] and the available vCPUs on the host.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt
index d668fdaf..f79d6d88 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostWeigher] that weighs the hosts based on the available memory per core on the host.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt
index aa8a9d53..01799122 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt
@@ -23,7 +23,7 @@
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.HostView
import org.opendc.compute.service.scheduler.FilterScheduler
/**
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt
index 732cbe03..bfb583a2 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostWeigher] that weighs the hosts based on the number of instances on the host.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RamWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RamWeigher.kt
index d18d31f4..bb837fbe 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RamWeigher.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RamWeigher.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostWeigher] that weighs the hosts based on the available RAM (memory) on the host.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt
index a86226e2..f15f60c9 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostWeigher] that weighs the hosts based on the difference required vCPU capacity and the available CPU capacity.
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt
index 4a22269b..169ad8cb 100644
--- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt
+++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt
@@ -23,7 +23,7 @@
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.HostView
/**
* A [HostWeigher] that weighs the hosts based on the remaining number of vCPUs available.
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 a64c0885..4dc1cfa8 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
@@ -50,6 +50,7 @@ import org.opendc.compute.service.scheduler.filters.VCpuFilter
import org.opendc.compute.service.scheduler.weights.RamWeigher
import org.opendc.simulator.kotlin.SimulationCoroutineScope
import org.opendc.simulator.kotlin.runSimulation
+import java.time.Duration
import java.util.UUID
/**
@@ -66,7 +67,7 @@ internal class ComputeServiceTest {
filters = listOf(ComputeFilter(), VCpuFilter(allocationRatio = 1.0), RamFilter(allocationRatio = 1.0)),
weighers = listOf(RamWeigher())
)
- service = ComputeService(scope.dispatcher, computeScheduler)
+ service = ComputeService(scope.dispatcher, computeScheduler, Duration.ofMinutes(5))
}
@Test
@@ -300,25 +301,6 @@ internal class ComputeServiceTest {
}
@Test
- fun testServerInvalidType() = scope.runSimulation {
- val host = mockk<Host>(relaxUnitFun = true)
- val server = mockk<Server>(relaxUnitFun = true)
- val listeners = mutableListOf<HostListener>()
-
- every { host.uid } returns UUID.randomUUID()
- every { host.model } returns HostModel(4 * 2600.0, 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)
-
- assertThrows<IllegalArgumentException> {
- listeners.forEach { it.onStateChanged(host, server, ServerState.RUNNING) }
- }
- }
-
- @Test
fun testServerDeploy() = scope.runSimulation {
val host = mockk<Host>(relaxUnitFun = true)
val listeners = mutableListOf<HostListener>()
diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalFlavorTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceFlavorTest.kt
index fe92f7f2..7938f789 100644
--- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalFlavorTest.kt
+++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceFlavorTest.kt
@@ -28,41 +28,27 @@ 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.UUID
/**
- * Test suite for the [InternalFlavor] implementation.
+ * Test suite for the [ServiceFlavor] implementation.
*/
-class InternalFlavorTest {
+class ServiceFlavorTest {
@Test
fun testEquality() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
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
+ val a = ServiceFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf<String, Any>())
+ val b = ServiceFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf<String, Any>())
assertEquals(a, b)
}
@Test
fun testInequalityWithDifferentType() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
- val a = InternalFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf())
+ val a = ServiceFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf<String, Any>())
val b = mockk<Flavor>(relaxUnitFun = true)
every { b.uid } returns UUID.randomUUID()
@@ -72,9 +58,9 @@ class InternalFlavorTest {
@Test
fun testInequalityWithIncorrectType() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
- val a = InternalFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf())
+ val a = ServiceFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf<String, Any>())
assertNotEquals(a, Unit)
}
diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalImageTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceImageTest.kt
index d60aa628..c36d75f4 100644
--- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalImageTest.kt
+++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceImageTest.kt
@@ -28,42 +28,27 @@ 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.UUID
/**
- * Test suite for the [InternalFlavor] implementation.
+ * Test suite for the [ServiceFlavor] implementation.
*/
-class InternalImageTest {
+class ServiceImageTest {
@Test
fun testEquality() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
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
+ val a = ServiceImage(service, uid, "test", mutableMapOf(), mutableMapOf<String, Any>())
+ val b = ServiceImage(service, uid, "test", mutableMapOf(), mutableMapOf<String, Any>())
assertEquals(a, b)
}
@Test
fun testInequalityWithDifferentType() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
- val a = InternalImage(service, uid, "test", mutableMapOf(), mutableMapOf())
+ val a = ServiceImage(service, uid, "test", mutableMapOf(), mutableMapOf<String, Any>())
val b = mockk<Image>(relaxUnitFun = true)
every { b.uid } returns UUID.randomUUID()
@@ -73,9 +58,9 @@ class InternalImageTest {
@Test
fun testInequalityWithIncorrectType() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
- val a = InternalImage(service, uid, "test", mutableMapOf(), mutableMapOf())
+ val a = ServiceImage(service, uid, "test", mutableMapOf(), mutableMapOf<String, Any>())
assertNotEquals(a, Unit)
}
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/ServiceServerTest.kt
index 05a8160e..f9fcd27b 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/ServiceServerTest.kt
@@ -22,7 +22,6 @@
package org.opendc.compute.service
-import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
@@ -35,51 +34,33 @@ 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.kotlin.runSimulation
import java.util.UUID
/**
- * Test suite for the [InternalServer] implementation.
+ * Test suite for the [ServiceServer] implementation.
*/
-class InternalServerTest {
+class ServiceServerTest {
@Test
fun testEquality() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- 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 = mockFlavor()
- val image = mockImage()
- val a = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
-
- val b = mockk<Server>(relaxUnitFun = true)
- every { b.uid } returns uid
+ val a = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
+ val b = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
assertEquals(a, b)
}
@Test
fun testInequalityWithDifferentType() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val a = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val a = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
val b = mockk<Server>(relaxUnitFun = true)
every { b.uid } returns UUID.randomUUID()
@@ -89,24 +70,24 @@ class InternalServerTest {
@Test
fun testInequalityWithIncorrectType() {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val a = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val a = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
assertNotEquals(a, Unit)
}
@Test
fun testStartTerminatedServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- every { service.schedule(any()) } answers { ComputeServiceImpl.SchedulingRequest(it.invocation.args[0] as InternalServer, 0) }
+ every { service.schedule(any()) } answers { ComputeService.SchedulingRequest(it.invocation.args[0] as ServiceServer, 0) }
server.start()
@@ -116,26 +97,26 @@ class InternalServerTest {
@Test
fun testStartDeletedServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- server.state = ServerState.DELETED
+ server.setState(ServerState.DELETED)
assertThrows<IllegalStateException> { server.start() }
}
@Test
fun testStartProvisioningServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- server.state = ServerState.PROVISIONING
+ server.setState(ServerState.PROVISIONING)
server.start()
@@ -144,13 +125,13 @@ class InternalServerTest {
@Test
fun testStartRunningServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- server.state = ServerState.RUNNING
+ server.setState(ServerState.RUNNING)
server.start()
@@ -159,12 +140,12 @@ class InternalServerTest {
@Test
fun testStopProvisioningServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
- val request = ComputeServiceImpl.SchedulingRequest(server, 0)
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
+ val request = ComputeService.SchedulingRequest(server, 0)
every { service.schedule(any()) } returns request
@@ -177,13 +158,13 @@ class InternalServerTest {
@Test
fun testStopTerminatedServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- server.state = ServerState.TERMINATED
+ server.setState(ServerState.TERMINATED)
server.stop()
assertEquals(ServerState.TERMINATED, server.state)
@@ -191,13 +172,13 @@ class InternalServerTest {
@Test
fun testStopDeletedServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- server.state = ServerState.DELETED
+ server.setState(ServerState.DELETED)
server.stop()
assertEquals(ServerState.DELETED, server.state)
@@ -205,29 +186,29 @@ class InternalServerTest {
@Test
fun testStopRunningServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>()
+ val service = mockk<ComputeService>()
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
val host = mockk<Host>(relaxUnitFun = true)
- server.state = ServerState.RUNNING
+ server.setState(ServerState.RUNNING)
server.host = host
server.stop()
yield()
- coVerify { host.stop(server) }
+ verify { host.stop(server) }
}
@Test
fun testDeleteProvisioningServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>(relaxUnitFun = true)
+ val service = mockk<ComputeService>(relaxUnitFun = true)
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
- val request = ComputeServiceImpl.SchedulingRequest(server, 0)
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
+ val request = ComputeService.SchedulingRequest(server, 0)
every { service.schedule(any()) } returns request
@@ -241,13 +222,13 @@ class InternalServerTest {
@Test
fun testDeleteTerminatedServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>(relaxUnitFun = true)
+ val service = mockk<ComputeService>(relaxUnitFun = true)
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- server.state = ServerState.TERMINATED
+ server.setState(ServerState.TERMINATED)
server.delete()
assertEquals(ServerState.DELETED, server.state)
@@ -257,13 +238,13 @@ class InternalServerTest {
@Test
fun testDeleteDeletedServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>(relaxUnitFun = true)
+ val service = mockk<ComputeService>(relaxUnitFun = true)
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
- server.state = ServerState.DELETED
+ server.setState(ServerState.DELETED)
server.delete()
assertEquals(ServerState.DELETED, server.state)
@@ -271,24 +252,24 @@ class InternalServerTest {
@Test
fun testDeleteRunningServer() = runSimulation {
- val service = mockk<ComputeServiceImpl>(relaxUnitFun = true)
+ val service = mockk<ComputeService>(relaxUnitFun = true)
val uid = UUID.randomUUID()
val flavor = mockFlavor()
val image = mockImage()
- val server = InternalServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf())
+ val server = ServiceServer(service, uid, "test", flavor, image, mutableMapOf(), mutableMapOf<String, Any>())
val host = mockk<Host>(relaxUnitFun = true)
- server.state = ServerState.RUNNING
+ server.setState(ServerState.RUNNING)
server.host = host
server.delete()
yield()
- coVerify { host.delete(server) }
+ verify { host.delete(server) }
verify { service.delete(server) }
}
- private fun mockFlavor(): InternalFlavor {
- val flavor = mockk<InternalFlavor>()
+ private fun mockFlavor(): ServiceFlavor {
+ val flavor = mockk<ServiceFlavor>()
every { flavor.name } returns "c5.large"
every { flavor.uid } returns UUID.randomUUID()
every { flavor.cpuCount } returns 2
@@ -296,8 +277,8 @@ class InternalServerTest {
return flavor
}
- private fun mockImage(): InternalImage {
- val image = mockk<InternalImage>()
+ private fun mockImage(): ServiceImage {
+ val image = mockk<ServiceImage>()
every { image.name } returns "ubuntu-20.04"
every { image.uid } returns UUID.randomUUID()
return image
diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt
index 4608bf37..4af6f7ec 100644
--- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt
+++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt
@@ -30,9 +30,9 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.api.assertThrows
import org.opendc.compute.api.Server
+import org.opendc.compute.service.HostView
import org.opendc.compute.service.driver.HostModel
import org.opendc.compute.service.driver.HostState
-import org.opendc.compute.service.internal.HostView
import org.opendc.compute.service.scheduler.filters.ComputeFilter
import org.opendc.compute.service.scheduler.filters.DifferentHostFilter
import org.opendc.compute.service.scheduler.filters.InstanceCountFilter