diff options
Diffstat (limited to 'opendc-compute/opendc-compute-service')
39 files changed, 0 insertions, 4248 deletions
diff --git a/opendc-compute/opendc-compute-service/build.gradle.kts b/opendc-compute/opendc-compute-service/build.gradle.kts deleted file mode 100644 index cd25e05c..00000000 --- a/opendc-compute/opendc-compute-service/build.gradle.kts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -description = "OpenDC Compute Service implementation" - -// Build configuration -plugins { - `kotlin-library-conventions` -} - -dependencies { - api(projects.opendcCompute.opendcComputeApi) - implementation(projects.opendcCommon) - implementation(libs.kotlin.logging) - implementation(project(mapOf("path" to ":opendc-simulator:opendc-simulator-compute"))) - - testImplementation(projects.opendcSimulator.opendcSimulatorCore) - testImplementation(libs.log4j.slf4j) - testRuntimeOnly(libs.log4j.core) - testRuntimeOnly(libs.log4j.slf4j) -} 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 deleted file mode 100644 index ad01ee57..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ComputeService.java +++ /dev/null @@ -1,637 +0,0 @@ -/* - * 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.Task; -import org.opendc.compute.api.TaskState; -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.opendc.simulator.compute.workload.SimWorkload; -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 tasks 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); - - private final int maxNumFailures; - - /** - * 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 tasks that should be launched by the service. - */ - private final Deque<SchedulingRequest> taskQueue = new ArrayDeque<>(); - - /** - * The active tasks in the system. - */ - private final Map<Task, Host> activeTasks = 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 tasks for this compute service. - */ - private final Map<UUID, ServiceTask> taskById = new HashMap<>(); - - private final List<ServiceTask> tasks = new ArrayList<>(); - - /** - * A [HostListener] used to track the active tasks. - */ - 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 Task task, @NotNull TaskState newState) { - final ServiceTask serviceTask = (ServiceTask) task; - - if (serviceTask.getHost() != host) { - // This can happen when a task is rescheduled and started on another machine, while being deleted from - // the old machine. - return; - } - - serviceTask.setState(newState); - - // TODO: move the removal of tasks when max Failures are reached to here - if (newState == TaskState.TERMINATED || newState == TaskState.DELETED || newState == TaskState.ERROR) { - LOGGER.info("task {} {} {} finished", task.getUid(), task.getName(), task.getFlavor()); - - if (activeTasks.remove(task) != null) { - tasksActive--; - } - - HostView hv = hostToView.get(host); - final ServiceFlavor flavor = serviceTask.getFlavor(); - if (hv != null) { - hv.provisionedCores -= flavor.getCoreCount(); - 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 tasksPending = 0; - private int tasksActive = 0; - - /** - * Construct a {@link ComputeService} instance. - */ - ComputeService(Dispatcher dispatcher, ComputeScheduler scheduler, Duration quantum, int maxNumFailures) { - this.clock = dispatcher.getTimeSource(); - this.scheduler = scheduler; - this.pacer = new Pacer(dispatcher, quantum.toMillis(), (time) -> doSchedule()); - this.maxNumFailures = maxNumFailures; - } - - /** - * 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 Task}s hosted by this service. - */ - public List<Task> getTasks() { - return Collections.unmodifiableList(tasks); - } - - /** - * 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.coreCount()); - 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 Task}. - */ - public Host lookupHost(Task task) { - if (task instanceof ServiceTask) { - return ((ServiceTask) task).getHost(); - } - - ServiceTask internal = Objects.requireNonNull(taskById.get(task.getUid()), "Invalid task 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, - tasks.size(), - tasksPending, - tasksActive); - } - - @Override - public void close() { - if (isClosed) { - return; - } - - isClosed = true; - pacer.cancel(); - } - - /** - * Enqueue the specified [task] to be scheduled onto a host. - */ - SchedulingRequest schedule(ServiceTask task) { - LOGGER.debug("Enqueueing task {} to be assigned to host", task.getUid()); - - long now = clock.millis(); - SchedulingRequest request = new SchedulingRequest(task, now); - - task.launchedAt = Instant.ofEpochMilli(now); - taskQueue.add(request); - tasksPending++; - 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(ServiceTask task) { - taskById.remove(task.getUid()); - tasks.remove(task); - } - - /** - * 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 (taskQueue.isEmpty()) { - return; - } - - pacer.enqueue(); - } - - /** - * Run a single scheduling iteration. - */ - private void doSchedule() { - // reorder tasks - - while (!taskQueue.isEmpty()) { - SchedulingRequest request = taskQueue.peek(); - - if (request.isCancelled) { - taskQueue.poll(); - tasksPending--; - continue; - } - - final ServiceTask task = request.task; - - // Remove task from scheduling if it has failed too many times - if (task.getNumFailures() > maxNumFailures) { - LOGGER.warn("Failed to spawn {}: Task has failed more than the allowed {} times", task, maxNumFailures); - - taskQueue.poll(); - tasksPending--; - task.setState(TaskState.TERMINATED); - continue; - } - - final ServiceFlavor flavor = task.getFlavor(); - final HostView hv = scheduler.select(request.task); - - if (hv == null || !hv.getHost().canFit(task)) { - LOGGER.trace("Task {} selected for scheduling but no capacity available for it at the moment", task); - - if (flavor.getMemorySize() > maxMemory || flavor.getCoreCount() > maxCores) { - // Remove the incoming image - taskQueue.poll(); - tasksPending--; - attemptsFailure++; - - LOGGER.warn("Failed to spawn {}: does not fit", task); - - task.setState(TaskState.TERMINATED); - continue; - } else { - break; - } - } - - Host host = hv.getHost(); - - // Remove request from queue - taskQueue.poll(); - tasksPending--; - - LOGGER.info("Assigned task {} to host {}", task, host); - - try { - task.host = host; - - host.spawn(task); - host.start(task); - - tasksActive++; - attemptsSuccess++; - - hv.instanceCount++; - hv.provisionedCores += flavor.getCoreCount(); - hv.availableMemory -= flavor.getMemorySize(); - - activeTasks.put(task, 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); - private int maxNumFailures = 10; - - 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; - } - - public Builder withMaxNumFailures(int maxNumFailures) { - this.maxNumFailures = maxNumFailures; - return this; - } - - /** - * Build a {@link ComputeService}. - */ - public ComputeService build() { - return new ComputeService(dispatcher, computeScheduler, quantum, maxNumFailures); - } - } - - /** - * 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 Task newTask( - @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"); - - ServiceTask task = new ServiceTask(service, uid, name, internalFlavor, internalImage, labels, meta); - - service.taskById.put(uid, task); - service.tasks.add(task); - - if (start) { - task.start(); - } - - return task; - } - - @Nullable - @Override - public Task findTask(@NotNull UUID id) { - checkOpen(); - return service.taskById.get(id); - } - - @NotNull - @Override - public List<Task> queryTasks() { - checkOpen(); - - return new ArrayList<>(service.tasks); - } - - @Override - public void close() { - isClosed = true; - } - - @Override - public String toString() { - return "ComputeService.Client"; - } - - @Nullable - @Override - public void rescheduleTask(@NotNull Task task, @NotNull SimWorkload workload) { - ServiceTask internalTask = (ServiceTask) findTask(task.getUid()); - Host from = service.lookupHost(internalTask); - - from.delete(internalTask); - - internalTask.host = null; - - internalTask.setWorkload(workload); - internalTask.start(); - } - } - - /** - * A request to schedule a {@link ServiceTask} onto one of the {@link Host}s. - */ - static class SchedulingRequest { - final ServiceTask task; - final long submitTime; - - boolean isCancelled; - - SchedulingRequest(ServiceTask task, long submitTime) { - this.task = task; - 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 deleted file mode 100644 index 6e2cdcb4..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/HostView.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 deleted file mode 100644 index 0f434a6a..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceFlavor.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 coreCount; - private final long memorySize; - private final Map<String, String> labels; - private final Map<String, ?> meta; - - ServiceFlavor( - ComputeService service, - UUID uid, - String name, - int coreCount, - long memorySize, - Map<String, String> labels, - Map<String, ?> meta) { - this.service = service; - this.uid = uid; - this.name = name; - this.coreCount = coreCount; - this.memorySize = memorySize; - this.labels = labels; - this.meta = meta; - } - - @Override - public int getCoreCount() { - return coreCount; - } - - @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 deleted file mode 100644 index 706be483..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceImage.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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/ServiceTask.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceTask.java deleted file mode 100644 index f0e2a82e..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/ServiceTask.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * 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.HashMap; -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.Task; -import org.opendc.compute.api.TaskState; -import org.opendc.compute.api.TaskWatcher; -import org.opendc.compute.service.driver.Host; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation of {@link Task} provided by {@link ComputeService}. - */ -public final class ServiceTask implements Task { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceTask.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 Map<String, ?> meta; - - private final List<TaskWatcher> watchers = new ArrayList<>(); - private TaskState state = TaskState.TERMINATED; - Instant launchedAt = null; - Host host = null; - private ComputeService.SchedulingRequest request = null; - - private int numFailures = 0; - - ServiceTask( - 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); - } - - public void setWorkload(Object _workload) { - Map<String, Object> new_meta = new HashMap<String, Object>(); - new_meta.put("workload", _workload); - - meta = new_meta; - } - - @NotNull - @Override - public TaskState getState() { - return state; - } - - @Nullable - @Override - public Instant getLaunchedAt() { - return launchedAt; - } - - /** - * Return the {@link Host} on which the task 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 task but request is already pending: doing nothing"); - case RUNNING: - LOGGER.debug("User tried to start task but task is already running"); - break; - case DELETED: - LOGGER.warn("User tried to start deleted task"); - throw new IllegalStateException("Task is deleted"); - default: - LOGGER.info("User requested to start task {}", uid); - setState(TaskState.PROVISIONING); - assert request == null : "Scheduling request already active"; - request = service.schedule(this); - break; - } - } - - @Override - public void stop() { - switch (state) { - case PROVISIONING: - cancelProvisioningRequest(); - setState(TaskState.TERMINATED); - break; - case RUNNING: - case ERROR: - final Host host = this.host; - if (host == null) { - throw new IllegalStateException("Task not running"); - } - host.stop(this); - break; - } - } - - @Override - public void watch(@NotNull TaskWatcher watcher) { - watchers.add(watcher); - } - - @Override - public void unwatch(@NotNull TaskWatcher 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(TaskState.DELETED); - break; - case RUNNING: - case ERROR: - final Host host = this.host; - if (host == null) { - throw new IllegalStateException("Task not running"); - } - host.delete(this); - service.delete(this); - setState(TaskState.DELETED); - break; - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ServiceTask task = (ServiceTask) o; - return service.equals(task.service) && uid.equals(task.uid); - } - - @Override - public int hashCode() { - return Objects.hash(service, uid); - } - - @Override - public String toString() { - return "Task[uid=" + uid + ",name=" + name + ",state=" + state + "]"; - } - - void setState(TaskState newState) { - if (this.state == newState) { - return; - } - - for (TaskWatcher watcher : watchers) { - watcher.onStateChanged(this, newState); - } - if (newState == TaskState.ERROR) { - this.numFailures++; - } - - this.state = newState; - } - - /** - * Cancel the provisioning request if active. - */ - private void cancelProvisioningRequest() { - final ComputeService.SchedulingRequest request = this.request; - if (request != null) { - this.request = null; - request.isCancelled = true; - } - } - - @Override - public int getNumFailures() { - return this.numFailures; - } -} diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/Host.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/Host.java deleted file mode 100644 index 546f774b..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/Host.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver; - -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import org.opendc.compute.api.Task; -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 {@link Task} instances. - */ -public interface Host { - /** - * Return a unique identifier representing the host. - */ - UUID getUid(); - - /** - * Return the name of this host. - */ - String getName(); - - /** - * Return the machine model of the host. - */ - HostModel getModel(); - - /** - * Return the state of the host. - */ - HostState getState(); - - /** - * Return the meta-data associated with the host. - */ - Map<String, ?> getMeta(); - - /** - * Return the {@link Task} instances known to the host. - */ - Set<Task> getInstances(); - - /** - * Determine whether the specified <code>task</code> can still fit on this host. - */ - boolean canFit(Task task); - - /** - * Register the specified <code>task</code> on the host. - */ - void spawn(Task task); - - /** - * Determine whether the specified <code>task</code> exists on the host. - */ - boolean contains(Task task); - - /** - * Start the task if it is currently not running on this host. - * - * @throws IllegalArgumentException if the task is not present on the host. - */ - void start(Task task); - - /** - * Stop the task if it is currently running on this host. - * - * @throws IllegalArgumentException if the task is not present on the host. - */ - void stop(Task task); - - /** - * Delete the specified <code>task</code> on this host and cleanup all resources associated with it. - */ - void delete(Task task); - - /** - * Add a [HostListener] to this host. - */ - void addListener(HostListener listener); - - /** - * Remove a [HostListener] from this host. - */ - void removeListener(HostListener listener); - - /** - * Query the system statistics of the host. - */ - HostSystemStats getSystemStats(); - - /** - * Query the system statistics of a {@link Task} that is located on this host. - * - * @param task The {@link Task} to obtain the system statistics of. - * @throws IllegalArgumentException if the task is not present on the host. - */ - GuestSystemStats getSystemStats(Task task); - - /** - * Query the CPU statistics of the host. - */ - HostCpuStats getCpuStats(); - - /** - * Query the CPU statistics of a {@link Task} that is located on this host. - * - * @param task The {@link Task} to obtain the CPU statistics of. - * @throws IllegalArgumentException if the task is not present on the host. - */ - GuestCpuStats getCpuStats(Task task); -} diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostListener.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostListener.java deleted file mode 100644 index 079c6cff..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostListener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver; - -import org.opendc.compute.api.Task; -import org.opendc.compute.api.TaskState; - -/** - * Listener interface for events originating from a {@link Host}. - */ -public interface HostListener { - /** - * This method is invoked when the state of <code>task</code> on <code>host</code> changes. - */ - default void onStateChanged(Host host, Task task, TaskState newState) {} - - /** - * This method is invoked when the state of a {@link Host} has changed. - */ - default void onStateChanged(Host host, HostState newState) {} -} diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java deleted file mode 100644 index 87464fe1..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver; - -/** - * Record describing the static machine properties of the host. - * - * @param cpuCapacity The total CPU capacity of the host in MHz. - * @param coreCount The number of logical processing cores available for this host. - * @param memoryCapacity The amount of memory available for this host in MB. - */ -public record HostModel(double cpuCapacity, int coreCount, long memoryCapacity) {} diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostState.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostState.java deleted file mode 100644 index ce12a67e..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostState.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver; - -/** - * The state of a host. - */ -public enum HostState { - /** - * The host is up and able to host guests. - */ - UP, - - /** - * The host is in a (forced) down state and unable to host any guests. - */ - DOWN, - - /** - * The host is in an error state and unable to host any guests. - */ - ERROR -} diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/GuestCpuStats.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/GuestCpuStats.java deleted file mode 100644 index 0b78c7ea..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/GuestCpuStats.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver.telemetry; - -/** - * Statistics about the CPUs of a guest. - * - * @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 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/java/org/opendc/compute/service/driver/telemetry/GuestSystemStats.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/GuestSystemStats.java deleted file mode 100644 index dbf98dd5..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/GuestSystemStats.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver.telemetry; - -import java.time.Duration; -import java.time.Instant; - -/** - * System-level statistics of a guest. - * - * @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 record GuestSystemStats(Duration uptime, Duration downtime, Instant bootTime) {} diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/HostCpuStats.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/HostCpuStats.java deleted file mode 100644 index d1c2328b..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/HostCpuStats.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver.telemetry; - -/** - * Statistics about the CPUs of a host. - * - * @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 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/java/org/opendc/compute/service/driver/telemetry/HostSystemStats.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/HostSystemStats.java deleted file mode 100644 index c0713f3c..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/telemetry/HostSystemStats.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.driver.telemetry; - -import java.time.Duration; -import java.time.Instant; - -/** - * System-level statistics of a host. - * - * @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 task started. - * @param powerDraw Instantaneous power draw 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 record HostSystemStats( - Duration uptime, - Duration downtime, - Instant bootTime, - double powerDraw, - double energyUsage, - int guestsTerminated, - int guestsRunning, - int guestsError, - int guestsInvalid) {} diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/telemetry/SchedulerStats.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/telemetry/SchedulerStats.java deleted file mode 100644 index fc044d8c..00000000 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/telemetry/SchedulerStats.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.telemetry; - -/** - * Statistics about the scheduling component of the [ComputeService]. - * - * @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 tasksTotal The number of tasks registered with the service. - * @param tasksPending The number of tasks that are pending to be scheduled. - * @param tasksActive The number of tasks that are currently managed by the service and running. - */ -public record SchedulerStats( - int hostsAvailable, - int hostsUnavailable, - long attemptsSuccess, - long attemptsFailure, - long attemptsError, - int tasksTotal, - int tasksPending, - int tasksActive) {} 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 deleted file mode 100644 index 42de9ebc..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeScheduler.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler - -import org.opendc.compute.api.Task -import org.opendc.compute.service.ComputeService -import org.opendc.compute.service.HostView - -/** - * A generic scheduler interface used by the [ComputeService] to select hosts to place [Task]s on. - */ -public interface ComputeScheduler { - /** - * Register the specified [host] to be used for scheduling. - */ - public fun addHost(host: HostView) - - /** - * Remove the specified [host] to be removed from the scheduling pool. - */ - public fun removeHost(host: HostView) - - /** - * Select a host for the specified [task]. - * - * @param task The server to select a host for. - * @return The host to schedule the server on or `null` if no server is available. - */ - public fun select(task: Task): HostView? -} diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeSchedulers.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeSchedulers.kt deleted file mode 100644 index 7fcc670f..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ComputeSchedulers.kt +++ /dev/null @@ -1,118 +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. - */ - -@file:JvmName("ComputeSchedulers") - -package org.opendc.compute.service.scheduler - -import org.opendc.compute.service.scheduler.filters.ComputeFilter -import org.opendc.compute.service.scheduler.filters.RamFilter -import org.opendc.compute.service.scheduler.filters.VCpuFilter -import org.opendc.compute.service.scheduler.weights.CoreRamWeigher -import org.opendc.compute.service.scheduler.weights.InstanceCountWeigher -import org.opendc.compute.service.scheduler.weights.RamWeigher -import org.opendc.compute.service.scheduler.weights.VCpuWeigher -import java.util.SplittableRandom -import java.util.random.RandomGenerator - -public enum class ComputeSchedulerEnum { - Mem, - MemInv, - CoreMem, - CoreMemInv, - ActiveServers, - ActiveServersInv, - ProvisionedCores, - ProvisionedCoresInv, - Random, - Replay, -} - -public fun createComputeScheduler( - name: String, - seeder: RandomGenerator, - placements: Map<String, String> = emptyMap(), -): ComputeScheduler { - return createComputeScheduler(ComputeSchedulerEnum.valueOf(name.uppercase()), seeder, placements) -} - -/** - * Create a [ComputeScheduler] for the experiment. - */ -public fun createComputeScheduler( - name: ComputeSchedulerEnum, - seeder: RandomGenerator, - placements: Map<String, String> = emptyMap(), -): ComputeScheduler { - val cpuAllocationRatio = 1.0 - val ramAllocationRatio = 1.5 - return when (name) { - ComputeSchedulerEnum.Mem -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(RamWeigher(multiplier = 1.0)), - ) - ComputeSchedulerEnum.MemInv -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(RamWeigher(multiplier = -1.0)), - ) - ComputeSchedulerEnum.CoreMem -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(CoreRamWeigher(multiplier = 1.0)), - ) - ComputeSchedulerEnum.CoreMemInv -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(CoreRamWeigher(multiplier = -1.0)), - ) - ComputeSchedulerEnum.ActiveServers -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(InstanceCountWeigher(multiplier = -1.0)), - ) - ComputeSchedulerEnum.ActiveServersInv -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(InstanceCountWeigher(multiplier = 1.0)), - ) - ComputeSchedulerEnum.ProvisionedCores -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(VCpuWeigher(cpuAllocationRatio, multiplier = 1.0)), - ) - ComputeSchedulerEnum.ProvisionedCoresInv -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = listOf(VCpuWeigher(cpuAllocationRatio, multiplier = -1.0)), - ) - ComputeSchedulerEnum.Random -> - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)), - weighers = emptyList(), - subsetSize = Int.MAX_VALUE, - random = SplittableRandom(seeder.nextLong()), - ) - ComputeSchedulerEnum.Replay -> ReplayScheduler(placements) - } -} 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 deleted file mode 100644 index 772a470d..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/FilterScheduler.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler - -import org.opendc.compute.api.Task -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 -import java.util.random.RandomGenerator -import kotlin.math.min - -/** - * A [ComputeScheduler] implementation that uses filtering and weighing passes to select - * the host to schedule a [Task] on. - * - * This implementation is based on the filter scheduler from OpenStack Nova. - * See: https://docs.openstack.org/nova/latest/user/filter-scheduler.html - * - * @param filters The list of filters to apply when searching for an appropriate host. - * @param weighers The list of weighers to apply when searching for an appropriate host. - * @param subsetSize The size of the subset of best hosts from which a target is randomly chosen. - * @param random A [RandomGenerator] instance for selecting - */ -public class FilterScheduler( - private val filters: List<HostFilter>, - private val weighers: List<HostWeigher>, - private val subsetSize: Int = 1, - private val random: RandomGenerator = SplittableRandom(0), -) : ComputeScheduler { - /** - * The pool of hosts available to the scheduler. - */ - private val hosts = mutableListOf<HostView>() - - init { - require(subsetSize >= 1) { "Subset size must be one or greater" } - } - - override fun addHost(host: HostView) { - hosts.add(host) - } - - override fun removeHost(host: HostView) { - hosts.remove(host) - } - - override fun select(task: Task): HostView? { - val hosts = hosts - val filteredHosts = hosts.filter { host -> filters.all { filter -> filter.test(host, task) } } - - val subset = - if (weighers.isNotEmpty()) { - val results = weighers.map { it.getWeights(filteredHosts, task) } - val weights = DoubleArray(filteredHosts.size) - - for (result in results) { - val min = result.min - val range = (result.max - min) - - // Skip result if all weights are the same - if (range == 0.0) { - continue - } - - val multiplier = result.multiplier - val factor = multiplier / range - - for ((i, weight) in result.weights.withIndex()) { - weights[i] += factor * (weight - min) - } - } - - weights.indices - .asSequence() - .sortedByDescending { weights[it] } - .map { filteredHosts[it] } - .take(subsetSize) - .toList() - } else { - filteredHosts - } - - // fixme: currently finding no matching hosts can result in an error - return when (val maxSize = min(subsetSize, subset.size)) { - 0 -> null - 1 -> subset[0] - else -> subset[random.nextInt(maxSize)] - } - } -} 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 deleted file mode 100644 index d1690ddf..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/ReplayScheduler.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler - -import mu.KotlinLogging -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * Policy replaying VM-cluster assignment. - * - * Within each cluster, the active servers on each node determine which node gets - * assigned the VM image. - */ -public class ReplayScheduler(private val vmPlacements: Map<String, String>) : ComputeScheduler { - private val logger = KotlinLogging.logger {} - - /** - * The pool of hosts available to the scheduler. - */ - private val hosts = mutableListOf<HostView>() - - override fun addHost(host: HostView) { - hosts.add(host) - } - - override fun removeHost(host: HostView) { - hosts.remove(host) - } - - override fun select(task: Task): HostView? { - val clusterName = - vmPlacements[task.name] - ?: throw IllegalStateException("Could not find placement data in VM placement file for VM ${task.name}") - val machinesInCluster = hosts.filter { it.host.name.contains(clusterName) } - - if (machinesInCluster.isEmpty()) { - logger.info { "Could not find any machines belonging to cluster $clusterName for image ${task.name}, assigning randomly." } - return hosts.maxByOrNull { it.availableMemory } - } - - return machinesInCluster.maxByOrNull { it.availableMemory } - ?: throw IllegalStateException("Cloud not find any machine and could not randomly assign") - } -} diff --git a/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 deleted file mode 100644 index 2ad626f3..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/ComputeFilter.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView -import org.opendc.compute.service.driver.HostState - -/** - * A [HostFilter] that filters on active hosts. - */ -public class ComputeFilter : HostFilter { - override fun test( - host: HostView, - task: Task, - ): Boolean { - val result = host.host.state == HostState.UP - return result - } - - override fun toString(): String = "ComputeFilter" -} 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 deleted file mode 100644 index ffafeaa9..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/DifferentHostFilter.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView -import java.util.UUID - -/** - * A [HostFilter] that ensures an instance is scheduled on a different host from a set of instances. - */ -public class DifferentHostFilter : HostFilter { - override fun test( - host: HostView, - task: Task, - ): Boolean { - @Suppress("UNCHECKED_CAST") - val affinityUUIDs = task.meta["scheduler_hint:different_host"] as? Set<UUID> ?: return true - return host.host.instances.none { it.uid in affinityUUIDs } - } -} 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 deleted file mode 100644 index f506127a..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/HostFilter.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView -import org.opendc.compute.service.scheduler.FilterScheduler - -/** - * A filter used by the [FilterScheduler] to filter hosts. - */ -public fun interface HostFilter { - /** - * Test whether the specified [host] should be included in the selection - * for scheduling the specified [task]. - */ - public fun test( - host: HostView, - task: Task, - ): Boolean -} 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 deleted file mode 100644 index 7d5eb400..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/InstanceCountFilter.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostFilter] that filters hosts based on the number of instances on the host. - * - * @param limit The maximum number of instances on the host. - */ -public class InstanceCountFilter(private val limit: Int) : HostFilter { - override fun test( - host: HostView, - task: Task, - ): Boolean { - return host.instanceCount < limit - } - - override fun toString(): String = "InstanceCountFilter[limit=$limit]" -} 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 deleted file mode 100644 index 0a28ccc6..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/RamFilter.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostFilter] that filters hosts based on the memory requirements of a [Task] and the RAM available on the host. - * - * @param allocationRatio Virtual RAM to physical RAM allocation ratio. - */ -public class RamFilter(private val allocationRatio: Double) : HostFilter { - override fun test( - host: HostView, - task: Task, - ): Boolean { - val requestedMemory = task.flavor.memorySize - val availableMemory = host.availableMemory - val memoryCapacity = host.host.model.memoryCapacity - - // Do not allow an instance to overcommit against itself, only against - // other instances. - if (requestedMemory > memoryCapacity) { - return false - } - - val limit = memoryCapacity * allocationRatio - val used = memoryCapacity - availableMemory - val usable = limit - used - - val result = usable >= requestedMemory - return result - } -} 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 deleted file mode 100644 index d8634285..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/SameHostFilter.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView -import java.util.UUID - -/** - * A [HostFilter] that ensures an instance is scheduled on the same host as all other instances in a set of instances. - */ -public class SameHostFilter : HostFilter { - override fun test( - host: HostView, - task: Task, - ): Boolean { - @Suppress("UNCHECKED_CAST") - val affinityUUIDs = task.meta["scheduler_hint:same_host"] as? Set<UUID> ?: return true - return host.host.instances.any { it.uid in affinityUUIDs } - } -} 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 deleted file mode 100644 index 5af7ccf0..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostFilter] that filters hosts based on the vCPU speed requirements of a [Task] and the available - * capacity on the host. - */ -public class VCpuCapacityFilter : HostFilter { - override fun test( - host: HostView, - task: Task, - ): Boolean { - val requiredCapacity = task.flavor.meta["cpu-capacity"] as? Double - val hostModel = host.host.model - val availableCapacity = hostModel.cpuCapacity - - return requiredCapacity == null || availableCapacity >= (requiredCapacity / task.flavor.coreCount) - } -} 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 deleted file mode 100644 index 442e58f6..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuFilter.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.filters - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostFilter] that filters hosts based on the vCPU requirements of a [Task] and the available vCPUs on the host. - * - * @param allocationRatio Virtual CPU to physical CPU allocation ratio. - */ -public class VCpuFilter(private val allocationRatio: Double) : HostFilter { - override fun test( - host: HostView, - task: Task, - ): Boolean { - val requested = task.flavor.coreCount - val totalCores = host.host.model.coreCount - val limit = totalCores * allocationRatio - - // Do not allow an instance to overcommit against itself, only against other instances - if (requested > totalCores) { - return false - } - - val availableCores = limit - host.provisionedCores - return availableCores >= requested - } -} 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 deleted file mode 100644 index 6e320bf4..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.weights - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the available memory per core on the host. - * - * @param multiplier Weight multiplier ratio. A positive value will result in the scheduler preferring hosts with more - * available core memory, and a negative number will result in the scheduler preferring hosts with less available core - * memory. - */ -public class CoreRamWeigher(override val multiplier: Double = 1.0) : HostWeigher { - override fun getWeight( - host: HostView, - task: Task, - ): Double { - return host.availableMemory.toDouble() - } - - override fun toString(): String = "CoreRamWeigher" -} 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 deleted file mode 100644 index 3f2c4123..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/HostWeigher.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.weights - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView -import org.opendc.compute.service.scheduler.FilterScheduler - -/** - * An interface used by the [FilterScheduler] to weigh the pool of host for a scheduling request. - */ -public interface HostWeigher { - /** - * The multiplier for the weigher. - */ - public val multiplier: Double - - /** - * Obtain the weight of the specified [host] when scheduling the specified [task]. - */ - public fun getWeight( - host: HostView, - task: Task, - ): Double - - /** - * Obtain the weights for [hosts] when scheduling the specified [task]. - */ - public fun getWeights( - hosts: List<HostView>, - task: Task, - ): Result { - val weights = DoubleArray(hosts.size) - var min = Double.MAX_VALUE - var max = Double.MIN_VALUE - - for ((i, host) in hosts.withIndex()) { - val weight = getWeight(host, task) - weights[i] = weight - min = kotlin.math.min(min, weight) - max = kotlin.math.max(max, weight) - } - - return Result(weights, min, max, multiplier) - } - - /** - * A result returned by the weigher. - * - * @param weights The weights returned by the weigher. - * @param min The minimum weight returned. - * @param max The maximum weight returned. - * @param multiplier The weight multiplier to use. - */ - public class Result( - public val weights: DoubleArray, - public val min: Double, - public val max: Double, - public val multiplier: Double, - ) -} 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 deleted file mode 100644 index 0789f109..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/InstanceCountWeigher.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.weights - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the number of instances on the host. - */ -public class InstanceCountWeigher(override val multiplier: Double = 1.0) : HostWeigher { - override fun getWeight( - host: HostView, - task: Task, - ): Double { - return host.instanceCount.toDouble() - } - - override fun toString(): String = "InstanceCountWeigher" -} 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 deleted file mode 100644 index fb03d064..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/RamWeigher.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.weights - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the available RAM (memory) on the host. - * - * @param multiplier Weight multiplier ratio. A positive value will result in the scheduler preferring hosts with more - * available memory, and a negative number will result in the scheduler preferring hosts with less memory. - */ -public class RamWeigher(override val multiplier: Double = 1.0) : HostWeigher { - override fun getWeight( - host: HostView, - task: Task, - ): Double { - return host.availableMemory.toDouble() - } - - override fun toString(): String = "RamWeigher" -} 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 deleted file mode 100644 index 5f99cab3..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.weights - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the difference required vCPU capacity and the available CPU capacity. - */ -public class VCpuCapacityWeigher(override val multiplier: Double = 1.0) : HostWeigher { - override fun getWeight( - host: HostView, - task: Task, - ): Double { - val model = host.host.model - val requiredCapacity = task.flavor.meta["cpu-capacity"] as? Double ?: 0.0 - return model.cpuCapacity - requiredCapacity / task.flavor.coreCount - } - - override fun toString(): String = "VCpuWeigher" -} 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 deleted file mode 100644 index 0c3d9c21..00000000 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler.weights - -import org.opendc.compute.api.Task -import org.opendc.compute.service.HostView - -/** - * A [HostWeigher] that weighs the hosts based on the remaining number of vCPUs available. - * - * @param allocationRatio Virtual CPU to physical CPU allocation ratio. - */ -public class VCpuWeigher(private val allocationRatio: Double, override val multiplier: Double = 1.0) : HostWeigher { - init { - require(allocationRatio > 0.0) { "Allocation ratio must be greater than zero" } - } - - override fun getWeight( - host: HostView, - task: Task, - ): Double { - return allocationRatio - host.provisionedCores - } - - override fun toString(): String = "VCpuWeigher" -} 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 deleted file mode 100644 index eb686faf..00000000 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service - -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.mockk -import io.mockk.slot -import io.mockk.verify -import kotlinx.coroutines.delay -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNull -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.compute.api.Flavor -import org.opendc.compute.api.Image -import org.opendc.compute.api.Task -import org.opendc.compute.api.TaskState -import org.opendc.compute.api.TaskWatcher -import org.opendc.compute.service.driver.Host -import org.opendc.compute.service.driver.HostListener -import org.opendc.compute.service.driver.HostModel -import org.opendc.compute.service.driver.HostState -import org.opendc.compute.service.scheduler.FilterScheduler -import org.opendc.compute.service.scheduler.filters.ComputeFilter -import org.opendc.compute.service.scheduler.filters.RamFilter -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 - -/** - * Test suite for the [ComputeService] interface. - */ -internal class ComputeServiceTest { - private lateinit var scope: SimulationCoroutineScope - private lateinit var service: ComputeService - - @BeforeEach - fun setUp() { - scope = SimulationCoroutineScope() - val computeScheduler = - FilterScheduler( - filters = listOf(ComputeFilter(), VCpuFilter(allocationRatio = 1.0), RamFilter(allocationRatio = 1.0)), - weighers = listOf(RamWeigher()), - ) - service = ComputeService(scope.dispatcher, computeScheduler, Duration.ofMinutes(5), 10) - } - - @Test - fun testClientClose() = - scope.runSimulation { - val client = service.newClient() - - assertEquals(emptyList<Flavor>(), client.queryFlavors()) - assertEquals(emptyList<Image>(), client.queryImages()) - assertEquals(emptyList<Task>(), client.queryTasks()) - - client.close() - - assertThrows<IllegalStateException> { client.queryFlavors() } - assertThrows<IllegalStateException> { client.queryImages() } - assertThrows<IllegalStateException> { client.queryTasks() } - - assertThrows<IllegalStateException> { client.findFlavor(UUID.randomUUID()) } - assertThrows<IllegalStateException> { client.findImage(UUID.randomUUID()) } - assertThrows<IllegalStateException> { client.findTask(UUID.randomUUID()) } - - assertThrows<IllegalStateException> { client.newFlavor("test", 1, 2) } - assertThrows<IllegalStateException> { client.newImage("test") } - assertThrows<IllegalStateException> { client.newTask("test", mockk(), mockk()) } - } - - @Test - fun testClientCreate() = - scope.runSimulation { - val client = service.newClient() - - val flavor = client.newFlavor("test", 1, 1024) - assertEquals(listOf(flavor), client.queryFlavors()) - assertEquals(flavor, client.findFlavor(flavor.uid)) - val image = client.newImage("test") - assertEquals(listOf(image), client.queryImages()) - assertEquals(image, client.findImage(image.uid)) - val server = client.newTask("test", image, flavor, start = false) - assertEquals(listOf(server), client.queryTasks()) - assertEquals(server, client.findTask(server.uid)) - - server.delete() - assertNull(client.findTask(server.uid)) - - image.delete() - assertNull(client.findImage(image.uid)) - - flavor.delete() - assertNull(client.findFlavor(flavor.uid)) - - assertThrows<IllegalStateException> { server.start() } - } - - @Test - fun testClientOnClose() = - scope.runSimulation { - service.close() - assertThrows<IllegalStateException> { - service.newClient() - } - } - - @Test - fun testAddHost() = - scope.runSimulation { - val host = mockk<Host>(relaxUnitFun = true) - - every { host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { host.state } returns HostState.UP - - assertEquals(emptySet<Host>(), service.hosts) - - service.addHost(host) - - verify(exactly = 1) { host.addListener(any()) } - - assertEquals(1, service.hosts.size) - - service.removeHost(host) - - verify(exactly = 1) { host.removeListener(any()) } - } - - @Test - fun testAddHostDouble() = - scope.runSimulation { - val host = mockk<Host>(relaxUnitFun = true) - - every { host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { host.state } returns HostState.DOWN - - assertEquals(emptySet<Host>(), service.hosts) - - service.addHost(host) - service.addHost(host) - - verify(exactly = 1) { host.addListener(any()) } - } - - @Test - fun testServerStartWithoutEnoughCpus() = - scope.runSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 0) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - server.start() - delay(5L * 60 * 1000) - server.reload() - assertEquals(TaskState.TERMINATED, server.state) - } - - @Test - fun testServerStartWithoutEnoughMemory() = - scope.runSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 0, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - server.start() - delay(5L * 60 * 1000) - server.reload() - assertEquals(TaskState.TERMINATED, server.state) - } - - @Test - fun testServerStartWithoutEnoughResources() = - scope.runSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - server.start() - delay(5L * 60 * 1000) - server.reload() - assertEquals(TaskState.TERMINATED, server.state) - } - - @Test - fun testServerCancelRequest() = - scope.runSimulation { - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - server.start() - server.stop() - delay(5L * 60 * 1000) - server.reload() - assertEquals(TaskState.TERMINATED, server.state) - } - - @Test - fun testServerCannotFitOnHost() = - scope.runSimulation { - val host = mockk<Host>(relaxUnitFun = true) - - every { host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { host.state } returns HostState.UP - every { host.canFit(any()) } returns false - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - server.start() - delay(10L * 60 * 1000) - server.reload() - assertEquals(TaskState.PROVISIONING, server.state) - - verify { host.canFit(server) } - } - - @Test - fun testHostAvailableAfterSomeTime() = - scope.runSimulation { - val host = mockk<Host>(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.DOWN - every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } - every { host.canFit(any()) } returns false - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - server.start() - delay(5L * 60 * 1000) - - every { host.state } returns HostState.UP - listeners.forEach { it.onStateChanged(host, HostState.UP) } - - delay(5L * 60 * 1000) - server.reload() - assertEquals(TaskState.PROVISIONING, server.state) - - verify { host.canFit(server) } - } - - @Test - fun testHostUnavailableAfterSomeTime() = - scope.runSimulation { - val host = mockk<Host>(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.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } - every { host.canFit(any()) } returns false - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - delay(5L * 60 * 1000) - - every { host.state } returns HostState.DOWN - listeners.forEach { it.onStateChanged(host, HostState.DOWN) } - - server.start() - delay(5L * 60 * 1000) - server.reload() - assertEquals(TaskState.PROVISIONING, server.state) - - verify(exactly = 0) { host.canFit(server) } - } - - @Test - fun testServerDeploy() = - scope.runSimulation { - val host = mockk<Host>(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) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - val slot = slot<Task>() - - val watcher = mockk<TaskWatcher>(relaxUnitFun = true) - server.watch(watcher) - - // Start server - server.start() - delay(5L * 60 * 1000) - coVerify { host.spawn(capture(slot)) } - - listeners.forEach { it.onStateChanged(host, slot.captured, TaskState.RUNNING) } - - server.reload() - assertEquals(TaskState.RUNNING, server.state) - - verify { watcher.onStateChanged(server, TaskState.RUNNING) } - - // Stop server - listeners.forEach { it.onStateChanged(host, slot.captured, TaskState.TERMINATED) } - - server.reload() - assertEquals(TaskState.TERMINATED, server.state) - - verify { watcher.onStateChanged(server, TaskState.TERMINATED) } - } - - @Test - fun testServerDeployFailure() = - scope.runSimulation { - val host = mockk<Host>(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) } - coEvery { host.spawn(any()) } throws IllegalStateException() - - service.addHost(host) - - val client = service.newClient() - val flavor = client.newFlavor("test", 1, 1024) - val image = client.newImage("test") - val server = client.newTask("test", image, flavor, start = false) - - server.start() - delay(5L * 60 * 1000) - - server.reload() - assertEquals(TaskState.PROVISIONING, server.state) - } -} diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceFlavorTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceFlavorTest.kt deleted file mode 100644 index 7938f789..00000000 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceFlavorTest.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service - -import io.mockk.every -import io.mockk.mockk -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test -import org.opendc.compute.api.Flavor -import java.util.UUID - -/** - * Test suite for the [ServiceFlavor] implementation. - */ -class ServiceFlavorTest { - @Test - fun testEquality() { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - 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<ComputeService>() - val uid = UUID.randomUUID() - val a = ServiceFlavor(service, uid, "test", 1, 1024, mutableMapOf(), mutableMapOf<String, Any>()) - - val b = mockk<Flavor>(relaxUnitFun = true) - every { b.uid } returns UUID.randomUUID() - - assertNotEquals(a, b) - } - - @Test - fun testInequalityWithIncorrectType() { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - 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/ServiceImageTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceImageTest.kt deleted file mode 100644 index c36d75f4..00000000 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceImageTest.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service - -import io.mockk.every -import io.mockk.mockk -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test -import org.opendc.compute.api.Image -import java.util.UUID - -/** - * Test suite for the [ServiceFlavor] implementation. - */ -class ServiceImageTest { - @Test - fun testEquality() { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - 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<ComputeService>() - val uid = UUID.randomUUID() - val a = ServiceImage(service, uid, "test", mutableMapOf(), mutableMapOf<String, Any>()) - - val b = mockk<Image>(relaxUnitFun = true) - every { b.uid } returns UUID.randomUUID() - - assertNotEquals(a, b) - } - - @Test - fun testInequalityWithIncorrectType() { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - 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/ServiceTaskTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceTaskTest.kt deleted file mode 100644 index e77665fe..00000000 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ServiceTaskTest.kt +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service - -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import kotlinx.coroutines.yield -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.compute.api.Task -import org.opendc.compute.api.TaskState -import org.opendc.compute.service.driver.Host -import org.opendc.simulator.kotlin.runSimulation -import java.util.UUID - -/** - * Test suite for the [ServiceTask] implementation. - */ -class ServiceTaskTest { - @Test - fun testEquality() { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - - val a = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - val b = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - assertEquals(a, b) - } - - @Test - fun testInequalityWithDifferentType() { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val a = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - val b = mockk<Task>(relaxUnitFun = true) - every { b.uid } returns UUID.randomUUID() - - assertNotEquals(a, b) - } - - @Test - fun testInequalityWithIncorrectType() { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val a = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - assertNotEquals(a, Unit) - } - - @Test - fun testStartTerminatedServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - every { service.schedule(any()) } answers { ComputeService.SchedulingRequest(it.invocation.args[0] as ServiceTask, 0) } - - server.start() - - verify(exactly = 1) { service.schedule(server) } - assertEquals(TaskState.PROVISIONING, server.state) - } - - @Test - fun testStartDeletedServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - server.setState(TaskState.DELETED) - - assertThrows<IllegalStateException> { server.start() } - } - - @Test - fun testStartProvisioningServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - server.setState(TaskState.PROVISIONING) - - server.start() - - assertEquals(TaskState.PROVISIONING, server.state) - } - - @Test - fun testStartRunningServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - server.setState(TaskState.RUNNING) - - server.start() - - assertEquals(TaskState.RUNNING, server.state) - } - - @Test - fun testStopProvisioningServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - val request = ComputeService.SchedulingRequest(server, 0) - - every { service.schedule(any()) } returns request - - server.start() - server.stop() - - assertTrue(request.isCancelled) - assertEquals(TaskState.TERMINATED, server.state) - } - - @Test - fun testStopTerminatedServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - server.setState(TaskState.TERMINATED) - server.stop() - - assertEquals(TaskState.TERMINATED, server.state) - } - - @Test - fun testStopDeletedServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - server.setState(TaskState.DELETED) - server.stop() - - assertEquals(TaskState.DELETED, server.state) - } - - @Test - fun testStopRunningServer() = - runSimulation { - val service = mockk<ComputeService>() - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - val host = mockk<Host>(relaxUnitFun = true) - - server.setState(TaskState.RUNNING) - server.host = host - server.stop() - yield() - - verify { host.stop(server) } - } - - @Test - fun testDeleteProvisioningServer() = - runSimulation { - val service = mockk<ComputeService>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - val request = ComputeService.SchedulingRequest(server, 0) - - every { service.schedule(any()) } returns request - - server.start() - server.delete() - - assertTrue(request.isCancelled) - assertEquals(TaskState.DELETED, server.state) - verify { service.delete(server) } - } - - @Test - fun testDeleteTerminatedServer() = - runSimulation { - val service = mockk<ComputeService>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - server.setState(TaskState.TERMINATED) - server.delete() - - assertEquals(TaskState.DELETED, server.state) - - verify { service.delete(server) } - } - - @Test - fun testDeleteDeletedServer() = - runSimulation { - val service = mockk<ComputeService>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - - server.setState(TaskState.DELETED) - server.delete() - - assertEquals(TaskState.DELETED, server.state) - } - - @Test - fun testDeleteRunningServer() = - runSimulation { - val service = mockk<ComputeService>(relaxUnitFun = true) - val uid = UUID.randomUUID() - val flavor = mockFlavor() - val image = mockImage() - val server = - ServiceTask( - service, - uid, - "test", - flavor, - image, - mutableMapOf(), - mutableMapOf<String, Any>(), - ) - val host = mockk<Host>(relaxUnitFun = true) - - server.setState(TaskState.RUNNING) - server.host = host - server.delete() - yield() - - verify { host.delete(server) } - verify { service.delete(server) } - } - - private fun mockFlavor(): ServiceFlavor { - val flavor = mockk<ServiceFlavor>() - every { flavor.name } returns "c5.large" - every { flavor.uid } returns UUID.randomUUID() - every { flavor.coreCount } returns 2 - every { flavor.memorySize } returns 4096 - return flavor - } - - 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 deleted file mode 100644 index add10f8f..00000000 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.compute.service.scheduler - -import io.mockk.every -import io.mockk.mockk -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNull -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertAll -import org.junit.jupiter.api.assertThrows -import org.opendc.compute.api.Task -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.scheduler.filters.ComputeFilter -import org.opendc.compute.service.scheduler.filters.DifferentHostFilter -import org.opendc.compute.service.scheduler.filters.InstanceCountFilter -import org.opendc.compute.service.scheduler.filters.RamFilter -import org.opendc.compute.service.scheduler.filters.SameHostFilter -import org.opendc.compute.service.scheduler.filters.VCpuCapacityFilter -import org.opendc.compute.service.scheduler.filters.VCpuFilter -import org.opendc.compute.service.scheduler.weights.CoreRamWeigher -import org.opendc.compute.service.scheduler.weights.InstanceCountWeigher -import org.opendc.compute.service.scheduler.weights.RamWeigher -import org.opendc.compute.service.scheduler.weights.VCpuWeigher -import java.util.Random -import java.util.UUID - -/** - * Test suite for the [FilterScheduler]. - */ -internal class FilterSchedulerTest { - @Test - fun testInvalidSubsetSize() { - assertThrows<IllegalArgumentException> { - FilterScheduler( - filters = emptyList(), - weighers = emptyList(), - subsetSize = 0, - ) - } - - assertThrows<IllegalArgumentException> { - FilterScheduler( - filters = emptyList(), - weighers = emptyList(), - subsetSize = -2, - ) - } - } - - @Test - fun testNoHosts() { - val scheduler = - FilterScheduler( - filters = emptyList(), - weighers = emptyList(), - ) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertNull(scheduler.select(task)) - } - - @Test - fun testNoFiltersAndSchedulers() { - val scheduler = - FilterScheduler( - filters = emptyList(), - weighers = emptyList(), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.DOWN - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - // Make sure we get the first host both times - assertAll( - { assertEquals(hostA, scheduler.select(task)) }, - { assertEquals(hostA, scheduler.select(task)) }, - ) - } - - @Test - fun testNoFiltersAndSchedulersRandom() { - val scheduler = - FilterScheduler( - filters = emptyList(), - weighers = emptyList(), - subsetSize = Int.MAX_VALUE, - random = Random(1), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.DOWN - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - // Make sure we get the first host both times - assertAll( - { assertEquals(hostB, scheduler.select(task)) }, - { assertEquals(hostA, scheduler.select(task)) }, - ) - } - - @Test - fun testHostIsDown() { - val scheduler = - FilterScheduler( - filters = listOf(ComputeFilter()), - weighers = emptyList(), - ) - - val host = mockk<HostView>() - every { host.host.state } returns HostState.DOWN - - scheduler.addHost(host) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertNull(scheduler.select(task)) - } - - @Test - fun testHostIsUp() { - val scheduler = - FilterScheduler( - filters = listOf(ComputeFilter()), - weighers = emptyList(), - ) - - val host = mockk<HostView>() - every { host.host.state } returns HostState.UP - - scheduler.addHost(host) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(host, scheduler.select(task)) - } - - @Test - fun testRamFilter() { - val scheduler = - FilterScheduler( - filters = listOf(RamFilter(1.0)), - weighers = emptyList(), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.availableMemory } returns 512 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.availableMemory } returns 2048 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(hostB, scheduler.select(task)) - } - - @Test - fun testRamFilterOvercommit() { - val scheduler = - FilterScheduler( - filters = listOf(RamFilter(1.5)), - weighers = emptyList(), - ) - - val host = mockk<HostView>() - every { host.host.state } returns HostState.UP - every { host.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { host.availableMemory } returns 2048 - - scheduler.addHost(host) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 2300 - - assertNull(scheduler.select(task)) - } - - @Test - fun testVCpuFilter() { - val scheduler = - FilterScheduler( - filters = listOf(VCpuFilter(1.0)), - weighers = emptyList(), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.provisionedCores } returns 3 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.provisionedCores } returns 0 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(hostB, scheduler.select(task)) - } - - @Test - fun testVCpuFilterOvercommit() { - val scheduler = - FilterScheduler( - filters = listOf(VCpuFilter(16.0)), - weighers = emptyList(), - ) - - val host = mockk<HostView>() - every { host.host.state } returns HostState.UP - every { host.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { host.provisionedCores } returns 0 - - scheduler.addHost(host) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 8 - every { task.flavor.memorySize } returns 1024 - - assertNull(scheduler.select(task)) - } - -// TODO: fix when schedulers are reworked -// @Test - fun testVCpuCapacityFilter() { - val scheduler = - FilterScheduler( - filters = listOf(VCpuCapacityFilter()), - weighers = emptyList(), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(8 * 2600.0, 8, 2048) - every { hostA.availableMemory } returns 512 - scheduler.addHost(hostA) - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 3200.0, 4, 2048) - every { hostB.availableMemory } returns 512 - - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - every { task.flavor.meta } returns mapOf("cpu-capacity" to 2 * 3200.0) - - assertEquals(hostB, scheduler.select(task)) - } - - @Test - fun testInstanceCountFilter() { - val scheduler = - FilterScheduler( - filters = listOf(InstanceCountFilter(limit = 2)), - weighers = emptyList(), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.instanceCount } returns 2 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.instanceCount } returns 0 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(hostB, scheduler.select(task)) - } - - @Test - fun testAffinityFilter() { - val scheduler = - FilterScheduler( - filters = listOf(SameHostFilter()), - weighers = emptyList(), - ) - - val taskA = mockk<Task>() - every { taskA.uid } returns UUID.randomUUID() - every { taskA.flavor.coreCount } returns 2 - every { taskA.flavor.memorySize } returns 1024 - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.host.instances } returns emptySet() - every { hostA.provisionedCores } returns 3 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.host.instances } returns setOf(taskA) - every { hostB.provisionedCores } returns 0 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val taskB = mockk<Task>() - every { taskB.flavor.coreCount } returns 2 - every { taskB.flavor.memorySize } returns 1024 - every { taskB.meta } returns emptyMap() - - assertEquals(hostA, scheduler.select(taskB)) - - every { taskB.meta } returns mapOf("scheduler_hint:same_host" to setOf(taskA.uid)) - - assertEquals(hostB, scheduler.select(taskB)) - } - - @Test - fun testAntiAffinityFilter() { - val scheduler = - FilterScheduler( - filters = listOf(DifferentHostFilter()), - weighers = emptyList(), - ) - - val taskA = mockk<Task>() - every { taskA.uid } returns UUID.randomUUID() - every { taskA.flavor.coreCount } returns 2 - every { taskA.flavor.memorySize } returns 1024 - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.host.instances } returns setOf(taskA) - every { hostA.provisionedCores } returns 3 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.host.instances } returns emptySet() - every { hostB.provisionedCores } returns 0 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val taskB = mockk<Task>() - every { taskB.flavor.coreCount } returns 2 - every { taskB.flavor.memorySize } returns 1024 - every { taskB.meta } returns emptyMap() - - assertEquals(hostA, scheduler.select(taskB)) - - every { taskB.meta } returns mapOf("scheduler_hint:different_host" to setOf(taskA.uid)) - - assertEquals(hostB, scheduler.select(taskB)) - } - - @Test - fun testRamWeigher() { - val scheduler = - FilterScheduler( - filters = emptyList(), - weighers = listOf(RamWeigher(1.5)), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.availableMemory } returns 1024 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.availableMemory } returns 512 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(hostA, scheduler.select(task)) - } - - // TODO: fix test when updating schedulers -// @Test - fun testCoreRamWeigher() { - val scheduler = - FilterScheduler( - filters = emptyList(), - weighers = listOf(CoreRamWeigher(1.5)), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(12 * 2600.0, 12, 2048) - every { hostA.availableMemory } returns 1024 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.availableMemory } returns 512 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(hostB, scheduler.select(task)) - } - - @Test - fun testVCpuWeigher() { - val scheduler = - FilterScheduler( - filters = emptyList(), - weighers = listOf(VCpuWeigher(16.0)), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.provisionedCores } returns 2 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.provisionedCores } returns 0 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(hostB, scheduler.select(task)) - } - - @Test - fun testInstanceCountWeigher() { - val scheduler = - FilterScheduler( - filters = emptyList(), - weighers = listOf(InstanceCountWeigher(multiplier = -1.0)), - ) - - val hostA = mockk<HostView>() - every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostA.instanceCount } returns 2 - - val hostB = mockk<HostView>() - every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) - every { hostB.instanceCount } returns 0 - - scheduler.addHost(hostA) - scheduler.addHost(hostB) - - val task = mockk<Task>() - every { task.flavor.coreCount } returns 2 - every { task.flavor.memorySize } returns 1024 - - assertEquals(hostB, scheduler.select(task)) - } -} diff --git a/opendc-compute/opendc-compute-service/src/test/resources/log4j2.xml b/opendc-compute/opendc-compute-service/src/test/resources/log4j2.xml deleted file mode 100644 index 0dfb75f2..00000000 --- a/opendc-compute/opendc-compute-service/src/test/resources/log4j2.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2021 AtLarge Research - ~ - ~ Permission is hereby granted, free of charge, to any person obtaining a copy - ~ of this software and associated documentation files (the "Software"), to deal - ~ in the Software without restriction, including without limitation the rights - ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - ~ copies of the Software, and to permit persons to whom the Software is - ~ furnished to do so, subject to the following conditions: - ~ - ~ The above copyright notice and this permission notice shall be included in all - ~ copies or substantial portions of the Software. - ~ - ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - ~ SOFTWARE. - --> - -<Configuration status="WARN" packages="org.apache.logging.log4j.core"> - <Appenders> - <Console name="Console" target="SYSTEM_OUT"> - <PatternLayout pattern="%d{HH:mm:ss.SSS} [%highlight{%-5level}] %logger{36} - %msg%n" disableAnsi="false"/> - </Console> - </Appenders> - <Loggers> - <Logger name="org.opendc" level="trace" additivity="false"> - <AppenderRef ref="Console"/> - </Logger> - <Root level="info"> - <AppenderRef ref="Console"/> - </Root> - </Loggers> -</Configuration> |
