diff options
Diffstat (limited to 'opendc-web/opendc-web-server/src/main')
37 files changed, 0 insertions, 3635 deletions
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java deleted file mode 100644 index a0ac390f..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java +++ /dev/null @@ -1,166 +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.web.server.model; - -import io.hypersistence.utils.hibernate.type.json.JsonType; -import io.quarkus.hibernate.orm.panache.Panache; -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import io.quarkus.hibernate.orm.panache.PanacheQuery; -import io.quarkus.panache.common.Parameters; -import jakarta.persistence.*; -import java.time.Instant; -import java.util.Map; -import org.hibernate.annotations.Type; -import org.opendc.web.proto.JobState; - -/** - * A simulation job to be run by the simulator. - */ -@Entity -@Table -@NamedQueries({ - @NamedQuery( - name = "Job.updateOne", - query = - """ - UPDATE Job j - SET j.state = :newState, j.updatedAt = :updatedAt, j.runtime = :runtime, j.results = :results - WHERE j.id = :id AND j.state = :oldState - """) -}) -public class Job extends PanacheEntityBase { - /** - * The main ID of a project. - * The value starts at 6 to account for the other 5 projects already made by the loading script. - */ - @Id - @SequenceGenerator(name = "jobSeq", sequenceName = "job_id_seq", allocationSize = 1, initialValue = 3) - @GeneratedValue(generator = "jobSeq") - public Long id; - - @ManyToOne(optional = false, fetch = FetchType.EAGER) - @JoinColumn(name = "scenario_id", foreignKey = @ForeignKey(name = "fk_jobs_scenario"), nullable = false) - public Scenario scenario; - - @Column(name = "created_by", nullable = false, updatable = false) - public String createdBy; - - @Column(name = "created_at", nullable = false, updatable = false) - public Instant createdAt; - - /** - * The number of simulation runs to perform. - */ - @Column(nullable = false, updatable = false) - public int repeats; - - /** - * The instant at which the job was updated. - */ - @Column(name = "updated_at", nullable = false) - public Instant updatedAt; - - /** - * The state of the job. - */ - @Enumerated(EnumType.STRING) - @Column(nullable = false) - public JobState state = JobState.PENDING; - - /** - * The runtime of the job (in seconds). - */ - @Column(nullable = false) - public int runtime = 0; - - /** - * Experiment results in JSON - */ - @Column(columnDefinition = "jsonb") - @Type(JsonType.class) - public Map<String, ?> results = null; - - /** - * Construct a {@link Job} instance. - */ - public Job(Scenario scenario, String createdBy, Instant createdAt, int repeats) { - this.createdBy = createdBy; - this.scenario = scenario; - this.createdAt = createdAt; - this.updatedAt = createdAt; - this.repeats = repeats; - } - - /** - * JPA constructor - */ - protected Job() {} - - /** - * Find {@link Job}s in the specified {@link JobState}. - * - * @param state The state of the jobs to find. - * @return A query for jobs that are in the specified state. - */ - public static PanacheQuery<Job> findByState(JobState state) { - return find("state", state); - } - - /** - * Atomically update this job. - * - * @param newState The new state to enter into. - * @param time The time at which the update occurs. - * @param results The results to possible set. - * @return <code>true</code> when the update succeeded`, <code>false</code> when there was a conflict. - */ - public boolean updateAtomically(JobState newState, Instant time, int runtime, Map<String, ?> results) { - long count = update( - "#Job.updateOne", - Parameters.with("id", id) - .and("oldState", state) - .and("newState", newState) - .and("updatedAt", time) - .and("runtime", runtime) - .and("results", results)); - Panache.getEntityManager().refresh(this); - return count > 0; - } - - /** - * Determine whether the job is allowed to transition to <code>newState</code>. - * - * @param newState The new state to transition to. - * @return <code>true</code> if the transition to the new state is legal, <code>false</code> otherwise. - */ - public boolean canTransitionTo(JobState newState) { - // Note that we always allow transitions from the state - return newState == this.state - || switch (this.state) { - case PENDING -> newState == JobState.CLAIMED; - case CLAIMED -> newState == JobState.RUNNING || newState == JobState.FAILED; - case RUNNING -> newState == JobState.FINISHED || newState == JobState.FAILED; - case FINISHED, FAILED -> false; - }; - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java deleted file mode 100644 index c2695192..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.model; - -import io.hypersistence.utils.hibernate.type.json.JsonType; -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import io.quarkus.hibernate.orm.panache.PanacheQuery; -import io.quarkus.panache.common.Parameters; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.Index; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OrderBy; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; -import java.util.HashSet; -import java.util.Set; -import org.hibernate.annotations.Type; -import org.opendc.web.proto.Targets; - -/** - * A portfolio is the composition of multiple scenarios. - */ -@Entity -@Table( - uniqueConstraints = { - @UniqueConstraint( - name = "uk_portfolios_number", - columnNames = {"project_id", "number"}) - }, - indexes = {@Index(name = "ux_portfolios_number", columnList = "project_id, number")}) -@NamedQueries({ - @NamedQuery(name = "Portfolio.findByProject", query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId"), - @NamedQuery( - name = "Portfolio.findOneByProject", - query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId AND p.number = :number") -}) -public class Portfolio extends PanacheEntityBase { - - /** - * The main ID of a project. - * The value starts at 6 to account for the other 5 projects already made by the loading script. - */ - @Id - @SequenceGenerator(name = "portfolioSeq", sequenceName = "portfolio_id_seq", allocationSize = 1, initialValue = 4) - @GeneratedValue(generator = "portfolioSeq") - public Long id; - - /** - * The {@link Project} this portfolio belongs to. - */ - @ManyToOne(optional = false) - @JoinColumn(name = "project_id", nullable = false) - public Project project; - - /** - * Unique number of the portfolio for the project. - */ - @Column(nullable = false) - public int number; - - /** - * The name of this portfolio. - */ - @Column(nullable = false) - public String name; - - /** - * The portfolio targets (metrics, repetitions). - */ - @Column(columnDefinition = "jsonb", nullable = false, updatable = false) - @Type(JsonType.class) - public Targets targets; - - /** - * The scenarios in this portfolio. - */ - @OneToMany( - cascade = {CascadeType.ALL}, - mappedBy = "portfolio", - orphanRemoval = true) - @OrderBy("id ASC") - public Set<Scenario> scenarios = new HashSet<>(); - - /** - * Construct a {@link Portfolio} object. - */ - public Portfolio(Project project, int number, String name, Targets targets) { - this.project = project; - this.number = number; - this.name = name; - this.targets = targets; - } - - /** - * JPA constructor - */ - protected Portfolio() {} - - /** - * Find all {@link Portfolio}s that belong to the specified project - * - * @param projectId The unique identifier of the project. - * @return The query of portfolios that belong to the specified project. - */ - public static PanacheQuery<Portfolio> findByProject(long projectId) { - return find("#Portfolio.findByProject", Parameters.with("projectId", projectId)); - } - - /** - * Find the {@link Portfolio} with the specified <code>number</code> belonging to the specified project. - * - * @param projectId The unique identifier of the project. - * @param number The number of the scenario. - * @return The portfolio or <code>null</code> if it does not exist. - */ - public static Portfolio findByProject(long projectId, int number) { - return find( - "#Portfolio.findOneByProject", - Parameters.with("projectId", projectId).and("number", number)) - .firstResult(); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java deleted file mode 100644 index f4e5305d..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java +++ /dev/null @@ -1,237 +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.web.server.model; - -import io.quarkus.hibernate.orm.panache.Panache; -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import io.quarkus.panache.common.Parameters; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OrderBy; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import java.time.Instant; -import java.util.HashSet; -import java.util.Set; - -/** - * A project in OpenDC encapsulates all the datacenter designs and simulation runs for a set of users. - */ -@Entity -@Table -@NamedQueries({ - @NamedQuery( - name = "Project.findByUser", - query = - """ - SELECT a - FROM ProjectAuthorization a - WHERE a.key.userName = :userName - """), - @NamedQuery( - name = "Project.allocatePortfolio", - query = - """ - UPDATE Project p - SET p.portfoliosCreated = :oldState + 1, p.updatedAt = :now - WHERE p.id = :id AND p.portfoliosCreated = :oldState - """), - @NamedQuery( - name = "Project.allocateTopology", - query = - """ - UPDATE Project p - SET p.topologiesCreated = :oldState + 1, p.updatedAt = :now - WHERE p.id = :id AND p.topologiesCreated = :oldState - """), - @NamedQuery( - name = "Project.allocateScenario", - query = - """ - UPDATE Project p - SET p.scenariosCreated = :oldState + 1, p.updatedAt = :now - WHERE p.id = :id AND p.scenariosCreated = :oldState - """) -}) -public class Project extends PanacheEntityBase { - - /** - * The main ID of a project. - * The value starts at 6 to account for the other 5 projects already made by the loading script. - */ - @Id - @SequenceGenerator(name = "projectSeq", sequenceName = "project_id_seq", allocationSize = 1, initialValue = 7) - @GeneratedValue(generator = "projectSeq") - public Long id; - - /** - * The name of the project. - */ - @Column(nullable = false) - public String name; - - /** - * The instant at which the project was created. - */ - @Column(name = "created_at", nullable = false, updatable = false) - public Instant createdAt; - - /** - * The instant at which the project was updated. - */ - @Column(name = "updated_at", nullable = false) - public Instant updatedAt; - - /** - * The portfolios belonging to this project. - */ - @OneToMany( - cascade = {CascadeType.ALL}, - mappedBy = "project", - orphanRemoval = true) - @OrderBy("id ASC") - public Set<Portfolio> portfolios = new HashSet<>(); - - /** - * The number of portfolios created for this project (including deleted portfolios). - */ - @Column(name = "portfolios_created", nullable = false) - public int portfoliosCreated = 0; - - /** - * The topologies belonging to this project. - */ - @OneToMany( - cascade = {CascadeType.ALL}, - mappedBy = "project", - orphanRemoval = true) - @OrderBy("id ASC") - public Set<Topology> topologies = new HashSet<>(); - - /** - * The number of topologies created for this project (including deleted topologies). - */ - @Column(name = "topologies_created", nullable = false) - public int topologiesCreated = 0; - - /** - * The scenarios belonging to this project. - */ - @OneToMany(mappedBy = "project", orphanRemoval = true) - public Set<Scenario> scenarios = new HashSet<>(); - - /** - * The number of scenarios created for this project (including deleted scenarios). - */ - @Column(name = "scenarios_created", nullable = false) - public int scenariosCreated = 0; - - /** - * The users authorized to access the project. - */ - @OneToMany( - cascade = {CascadeType.ALL}, - mappedBy = "project", - orphanRemoval = true) - public Set<ProjectAuthorization> authorizations = new HashSet<>(); - - /** - * Construct a {@link Project} object. - */ - public Project(String name, Instant createdAt) { - this.name = name; - this.createdAt = createdAt; - this.updatedAt = createdAt; - } - - /** - * JPA constructor - */ - protected Project() {} - - /** - * Allocate the next portfolio number for the specified [project]. - * - * @param time The time at which the new portfolio is created. - */ - public int allocatePortfolio(Instant time) { - for (int i = 0; i < 4; i++) { - long count = update( - "#Project.allocatePortfolio", - Parameters.with("id", id).and("oldState", portfoliosCreated).and("now", time)); - if (count > 0) { - return portfoliosCreated + 1; - } else { - Panache.getEntityManager().refresh(this); - } - } - - throw new IllegalStateException("Failed to allocate next portfolio"); - } - - /** - * Allocate the next topology number for the specified [project]. - * - * @param time The time at which the new topology is created. - */ - public int allocateTopology(Instant time) { - for (int i = 0; i < 4; i++) { - long count = update( - "#Project.allocateTopology", - Parameters.with("id", id).and("oldState", topologiesCreated).and("now", time)); - if (count > 0) { - return topologiesCreated + 1; - } else { - Panache.getEntityManager().refresh(this); - } - } - - throw new IllegalStateException("Failed to allocate next topology"); - } - - /** - * Allocate the next scenario number for the specified [project]. - * - * @param time The time at which the new scenario is created. - */ - public int allocateScenario(Instant time) { - for (int i = 0; i < 4; i++) { - long count = update( - "#Project.allocateScenario", - Parameters.with("id", id).and("oldState", scenariosCreated).and("now", time)); - if (count > 0) { - return scenariosCreated + 1; - } else { - Panache.getEntityManager().refresh(this); - } - } - - throw new IllegalStateException("Failed to allocate next scenario"); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java deleted file mode 100644 index 3776ae12..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java +++ /dev/null @@ -1,172 +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.web.server.model; - -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import io.quarkus.hibernate.orm.panache.PanacheQuery; -import io.quarkus.panache.common.Parameters; -import jakarta.persistence.Column; -import jakarta.persistence.Embeddable; -import jakarta.persistence.EmbeddedId; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.ForeignKey; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.MapsId; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.Table; -import java.io.Serializable; -import java.util.Objects; -import org.opendc.web.proto.user.ProjectRole; - -/** - * An authorization for some user to participate in a project. - */ -@Entity -@Table -@NamedQueries({ - @NamedQuery( - name = "ProjectAuthorization.findByUser", - query = - """ - SELECT a - FROM ProjectAuthorization a - WHERE a.key.userName = :userName - """), -}) -public class ProjectAuthorization extends PanacheEntityBase { - /** - * The user identifier of the authorization. - */ - @EmbeddedId - public ProjectAuthorization.Key key; - - /** - * The project that the user is authorized to participate in. - */ - @ManyToOne(optional = false, fetch = FetchType.LAZY) - @MapsId("projectId") - @JoinColumn( - name = "project_id", - updatable = false, - insertable = false, - nullable = false, - foreignKey = @ForeignKey(name = "fk_project_authorizations")) - public Project project; - - /** - * The role of the user in the project. - */ - @Column(nullable = false) - @Enumerated(EnumType.STRING) - public ProjectRole role; - - /** - * Construct a {@link ProjectAuthorization} object. - */ - public ProjectAuthorization(Project project, String userName, ProjectRole role) { - this.key = new ProjectAuthorization.Key(project.id, userName); - this.project = project; - this.role = role; - } - - /** - * JPA constructor - */ - protected ProjectAuthorization() {} - - /** - * List all projects for the user with the specified <code>userName</code>. - * - * @param userName The identifier of the user that is requesting the list of projects. - * @return A query returning projects that the user has received authorization for. - */ - public static PanacheQuery<ProjectAuthorization> findByUser(String userName) { - return find("#ProjectAuthorization.findByUser", Parameters.with("userName", userName)); - } - - /** - * Find the project with <code>id</code> for the user with the specified <code>userName</code>. - * - * @param userName The identifier of the user that is requesting the list of projects. - * @param project_id The unique identifier of the project. - * @return The project with the specified identifier or <code>null</code> if it does not exist or is not accessible - * to the user with the specified identifier. - */ - public static ProjectAuthorization findByUser(String userName, long project_id) { - return findById(new ProjectAuthorization.Key(project_id, userName)); - } - - /** - * Determine whether the authorization allows the user to edit the project. - */ - public boolean canEdit() { - return switch (role) { - case OWNER, EDITOR -> true; - case VIEWER -> false; - }; - } - - /** - * Determine whether the authorization allows the user to delete the project. - */ - public boolean canDelete() { - return role == ProjectRole.OWNER; - } - - /** - * Key for representing a {@link ProjectAuthorization} object. - */ - @Embeddable - public static class Key implements Serializable { - @Column(name = "project_id", nullable = false) - public long projectId; - - @Column(name = "user_name", nullable = false) - public String userName; - - public Key(long projectId, String userName) { - this.projectId = projectId; - this.userName = userName; - } - - protected Key() {} - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Key key = (Key) o; - return projectId == key.projectId && userName.equals(key.userName); - } - - @Override - public int hashCode() { - return Objects.hash(projectId, userName); - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java deleted file mode 100644 index c79ef5bb..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.model; - -import io.hypersistence.utils.hibernate.type.json.JsonType; -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import io.quarkus.hibernate.orm.panache.PanacheQuery; -import io.quarkus.panache.common.Parameters; -import jakarta.persistence.*; -import java.util.ArrayList; -import java.util.List; -import org.hibernate.annotations.Type; -import org.opendc.web.proto.OperationalPhenomena; - -/** - * A single scenario to be explored by the simulator. - */ -@Entity -@Table( - uniqueConstraints = { - @UniqueConstraint( - name = "uk_scenarios_number", - columnNames = {"project_id", "number"}) - }, - indexes = {@Index(name = "ux_scenarios_number", columnList = "project_id, number")}) -@NamedQueries({ - @NamedQuery(name = "Scenario.findByProject", query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId"), - @NamedQuery( - name = "Scenario.findByPortfolio", - query = - """ - SELECT s - FROM Scenario s - JOIN Portfolio p ON p.id = s.portfolio.id AND p.number = :number - WHERE s.project.id = :projectId - """), - @NamedQuery( - name = "Scenario.findOneByProject", - query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId AND s.number = :number") -}) -public class Scenario extends PanacheEntityBase { - /** - * The main ID of a Scenario. - * The value starts at 3 to account for the other 2 scenarios already made by the loading script. - */ - @Id - @SequenceGenerator(name = "scenarioSeq", sequenceName = "scenario_id_seq", allocationSize = 1, initialValue = 3) - @GeneratedValue(generator = "scenarioSeq") - public Long id; - - /** - * The {@link Project} to which this scenario belongs. - */ - @ManyToOne(optional = false) - @JoinColumn(name = "project_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_project")) - public Project project; - - /** - * The {@link Portfolio} to which this scenario belongs. - */ - @ManyToOne(optional = false) - @JoinColumn(name = "portfolio_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_portfolio")) - public Portfolio portfolio; - - /** - * Unique number of the scenario for the project. - */ - @Column(nullable = false) - public int number; - - /** - * The name of the scenario. - */ - @Column(nullable = false, updatable = false) - public String name; - - /** - * Workload details of the scenario. - */ - @Embedded - public Workload workload; - - /** - * Topology details of the scenario. - */ - @ManyToOne(optional = false) - @JoinColumn(name = "topology_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_topology")) - public Topology topology; - - /** - * Operational phenomena activated in the scenario. - * @Column(columnDefinition = "jsonb", nullable = false, updatable = false) - * @Type(JsonType.class) - */ - @Column(columnDefinition = "jsonb", nullable = false, updatable = false) - @Type(JsonType.class) - public OperationalPhenomena phenomena; - - /** - * The name of the VM scheduler used in the scenario. - */ - @Column(name = "scheduler_name", nullable = false, updatable = false) - public String schedulerName; - - /** - * The {@link Job} associated with the scenario. - */ - @OneToMany( - cascade = {CascadeType.ALL}, - mappedBy = "scenario", - fetch = FetchType.LAZY) - public List<Job> jobs = new ArrayList<>(); - - /** - * Construct a {@link Scenario} object. - */ - public Scenario( - Project project, - Portfolio portfolio, - int number, - String name, - Workload workload, - Topology topology, - OperationalPhenomena phenomena, - String schedulerName) { - this.project = project; - this.portfolio = portfolio; - this.number = number; - this.name = name; - this.workload = workload; - this.topology = topology; - this.phenomena = phenomena; - this.schedulerName = schedulerName; - } - - /** - * JPA constructor - */ - protected Scenario() {} - - /** - * Find all {@link Scenario}s that belong to the specified project - * - * @param projectId The unique identifier of the project. - * @return The query of scenarios that belong to the specified project. - */ - public static PanacheQuery<Scenario> findByProject(long projectId) { - return find("#Scenario.findByProject", Parameters.with("projectId", projectId)); - } - - /** - * Find all {@link Scenario}s that belong to the specified portfolio. - * - * @param projectId The unique identifier of the project. - * @param number The number of the portfolio. - * @return The query of scenarios that belong to the specified project and portfolio.. - */ - public static PanacheQuery<Scenario> findByPortfolio(long projectId, int number) { - return find( - "#Scenario.findByPortfolio", - Parameters.with("projectId", projectId).and("number", number)); - } - - /** - * Find the {@link Scenario} with the specified <code>number</code> belonging to the specified project. - * - * @param projectId The unique identifier of the project. - * @param number The number of the scenario. - * @return The scenario or <code>null</code> if it does not exist. - */ - public static Scenario findByProject(long projectId, int number) { - return find( - "#Scenario.findOneByProject", - Parameters.with("projectId", projectId).and("number", number)) - .firstResult(); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java deleted file mode 100644 index 8a4e2ae2..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java +++ /dev/null @@ -1,153 +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.web.server.model; - -import io.hypersistence.utils.hibernate.type.json.JsonType; -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import io.quarkus.hibernate.orm.panache.PanacheQuery; -import io.quarkus.panache.common.Parameters; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.Index; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; -import java.time.Instant; -import java.util.List; -import org.hibernate.annotations.Type; -import org.opendc.web.proto.Room; - -/** - * A datacenter design in OpenDC. - */ -@Entity -@Table( - uniqueConstraints = { - @UniqueConstraint( - name = "uk_topologies_number", - columnNames = {"project_id", "number"}) - }, - indexes = {@Index(name = "ux_topologies_number", columnList = "project_id, number")}) -@NamedQueries({ - @NamedQuery(name = "Topology.findByProject", query = "SELECT t FROM Topology t WHERE t.project.id = :projectId"), - @NamedQuery( - name = "Topology.findOneByProject", - query = "SELECT t FROM Topology t WHERE t.project.id = :projectId AND t.number = :number") -}) -public class Topology extends PanacheEntityBase { - /** - * The main ID of a project. - * The value starts at 6 to account for the other 5 projects already made by the loading script. - */ - @Id - @SequenceGenerator(name = "topologySeq", sequenceName = "topology_id_seq", allocationSize = 1, initialValue = 5) - @GeneratedValue(generator = "topologySeq") - public Long id; - - /** - * The {@link Project} to which the topology belongs. - */ - @ManyToOne(optional = false) - @JoinColumn(name = "project_id", nullable = false) - public Project project; - - /** - * Unique number of the topology for the project. - */ - @Column(nullable = false) - public int number; - - /** - * The name of the topology. - */ - @Column(nullable = false) - public String name; - - /** - * The instant at which the topology was created. - */ - @Column(name = "created_at", nullable = false, updatable = false) - public Instant createdAt; - - /** - * The instant at which the topology was updated. - */ - @Column(name = "updated_at", nullable = false) - public Instant updatedAt; - - /** - * Datacenter design in JSON - * @Column(columnDefinition = "jsonb", nullable = false) - * @Type(JsonType.class) - */ - @Column(columnDefinition = "jsonb", nullable = false) - @Type(JsonType.class) - public List<Room> rooms; - - /** - * Construct a {@link Topology} object. - */ - public Topology(Project project, int number, String name, Instant createdAt, List<Room> rooms) { - this.project = project; - this.number = number; - this.name = name; - this.createdAt = createdAt; - this.updatedAt = createdAt; - this.rooms = rooms; - } - - /** - * JPA constructor - */ - protected Topology() {} - - /** - * Find all [Topology]s that belong to [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @return The query of topologies that belong to the specified project. - */ - public static PanacheQuery<Topology> findByProject(long projectId) { - return find("#Topology.findByProject", Parameters.with("projectId", projectId)); - } - - /** - * Find the [Topology] with the specified [number] belonging to [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @param number The number of the topology. - * @return The topology or `null` if it does not exist. - */ - public static Topology findByProject(long projectId, int number) { - return find( - "#Topology.findOneByProject", - Parameters.with("projectId", projectId).and("number", number)) - .firstResult(); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java deleted file mode 100644 index 71c647bc..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java +++ /dev/null @@ -1,72 +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.web.server.model; - -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; - -/** - * A workload trace available for simulation. - */ -@Entity -@Table -public class Trace extends PanacheEntityBase { - /** - * The unique identifier of the trace. - */ - @Id - public String id; - - /** - * The name of the trace. - */ - @Column(nullable = false, updatable = false) - public String name; - - /** - * The type of trace. - */ - @Column(nullable = false, updatable = false) - public String type; - - /** - * Construct a {@link Trace}. - * - * @param id The unique identifier of the trace. - * @param name The name of the trace. - * @param type The type of trace. - */ - public Trace(String id, String name, String type) { - this.id = id; - this.name = name; - this.type = type; - } - - /** - * JPA constructor. - */ - protected Trace() {} -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java deleted file mode 100644 index 10a10ef9..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.model; - -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; -import io.quarkus.panache.common.Parameters; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.Table; -import java.time.LocalDate; - -/** - * Entity to track the number of simulation minutes used by a user. - */ -@Entity -@Table -@NamedQueries({ - @NamedQuery( - name = "UserAccounting.consumeBudget", - query = - """ - UPDATE UserAccounting a - SET a.simulationTime = a.simulationTime + :seconds - WHERE a.userId = :userId AND a.periodEnd = :periodEnd - """), - @NamedQuery( - name = "UserAccounting.resetBudget", - query = - """ - UPDATE UserAccounting a - SET a.periodEnd = :periodEnd, a.simulationTime = :seconds - WHERE a.userId = :userId AND a.periodEnd = :oldPeriodEnd - """) -}) -public class UserAccounting extends PanacheEntityBase { - /** - * User to which this object belongs. - */ - @Id - @Column(name = "user_id", nullable = false) - public String userId; - - /** - * The end of the accounting period. - */ - @Column(name = "period_end", nullable = false) - public LocalDate periodEnd; - - /** - * The number of simulation seconds to be used per accounting period. - */ - @Column(name = "simulation_time_budget", nullable = false) - public int simulationTimeBudget; - - /** - * The number of simulation seconds used in this period. This number should reset once the accounting period has - * been reached. - */ - @Column(name = "simulation_time", nullable = false) - public int simulationTime = 0; - - /** - * Construct a new {@link UserAccounting} object. - * - * @param userId The identifier of the user that this object belongs to. - * @param periodEnd The end of the accounting period. - * @param simulationTimeBudget The number of simulation seconds available per accounting period. - */ - public UserAccounting(String userId, LocalDate periodEnd, int simulationTimeBudget) { - this.userId = userId; - this.periodEnd = periodEnd; - this.simulationTimeBudget = simulationTimeBudget; - } - - /** - * JPA constructor. - */ - protected UserAccounting() {} - - /** - * Return the {@link UserAccounting} object associated with the specified user id. - */ - public static UserAccounting findByUser(String userId) { - return findById(userId); - } - - /** - * Create a new {@link UserAccounting} object and persist it to the database. - * - * @param userId The identifier of the user that this object belongs to. - * @param periodEnd The end of the accounting period. - * @param simulationTimeBudget The number of simulation seconds available per accounting period. - * @param simulationTime The initial simulation time that has been consumed. - */ - public static UserAccounting create( - String userId, LocalDate periodEnd, int simulationTimeBudget, int simulationTime) { - UserAccounting newAccounting = new UserAccounting(userId, periodEnd, simulationTimeBudget); - newAccounting.simulationTime = simulationTime; - newAccounting.persistAndFlush(); - return newAccounting; - } - - /** - * Atomically consume the budget for this {@link UserAccounting} object. - * - * @param seconds The number of seconds to consume from the user. - * @return <code>true</code> when the update succeeded, <code>false</code> when there was a conflict. - */ - public boolean consumeBudget(int seconds) { - long count = update( - "#UserAccounting.consumeBudget", - Parameters.with("userId", userId).and("periodEnd", periodEnd).and("seconds", seconds)); - return count > 0; - } - - /** - * Atomically reset the budget for this {@link UserAccounting} object. - * - * @param periodEnd The new end period for the budget. - * @param seconds The number of seconds that have already been consumed. - * @return <code>true</code> when the update succeeded`, <code>false</code> when there was a conflict. - */ - public boolean resetBudget(LocalDate periodEnd, int seconds) { - long count = update( - "#UserAccounting.resetBudget", - Parameters.with("userId", userId) - .and("oldPeriodEnd", this.periodEnd) - .and("periodEnd", periodEnd) - .and("seconds", seconds)); - return count > 0; - } - - /** - * Determine whether the user has any remaining simulation budget. - * - * @return <code>true</code> when the user still has budget left, <code>false</code> otherwise. - */ - public boolean hasSimulationBudget() { - var today = LocalDate.now(); - - // The accounting period must be over or there must be budget remaining. - return !today.isBefore(periodEnd) || simulationTimeBudget > simulationTime; - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java deleted file mode 100644 index fd7010d2..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.model; - -import jakarta.persistence.Column; -import jakarta.persistence.Embeddable; -import jakarta.persistence.ManyToOne; - -/** - * Specification of the workload for a {@link Scenario} - */ -@Embeddable -public class Workload { - /** - * The {@link Trace} that the workload runs. - */ - @ManyToOne(optional = false) - public Trace trace; - - /** - * The percentage of the trace that should be sampled. - */ - @Column(name = "sampling_fraction", nullable = false, updatable = false) - public double samplingFraction; - - /** - * Construct a {@link Workload} object. - * - * @param trace The {@link Trace} to run as workload. - * @param samplingFraction The percentage of the workload to sample. - */ - public Workload(Trace trace, double samplingFraction) { - this.trace = trace; - this.samplingFraction = samplingFraction; - } - - /** - * JPA constructor. - */ - protected Workload() {} -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java deleted file mode 100644 index 44d2d569..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest; - -import org.opendc.web.server.model.Trace; -import org.opendc.web.server.model.Workload; - -/** - * DTO-conversions for the base protocol. - */ -public final class BaseProtocol { - /** - * Private constructor to prevent instantiation of class. - */ - private BaseProtocol() {} - - /** - * Convert a {@link Workload} entity into a DTO. - */ - public static org.opendc.web.proto.Workload toDto(Workload workload) { - return new org.opendc.web.proto.Workload(toDto(workload.trace), workload.samplingFraction); - } - - /** - * Convert a {@link Trace] entity into a {@link org.opendc.web.proto.Trace} DTO. - */ - public static org.opendc.web.proto.Trace toDto(Trace trace) { - return new org.opendc.web.proto.Trace(trace.id, trace.name, trace.type); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java deleted file mode 100644 index 3e839040..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import java.util.List; - -/** - * A resource representing the available schedulers that can be used during experiments. - */ -@Produces("application/json") -@Path("/schedulers") -public final class SchedulerResource { - /** - * Obtain all available schedulers. - */ - @GET - public List<String> getAll() { - return List.of( - "mem", - "mem-inv", - "core-mem", - "core-mem-inv", - "active-tasks", - "active-tasks-inv", - "provisioned-cores", - "provisioned-cores-inv", - "random"); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java deleted file mode 100644 index daec01cd..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import java.util.List; -import java.util.stream.Stream; -import org.opendc.web.server.model.Trace; - -/** - * A resource representing the workload traces available in the OpenDC instance. - */ -@Produces("application/json") -@Path("/traces") -public final class TraceResource { - /** - * Obtain all available traces. - */ - @GET - public List<org.opendc.web.proto.Trace> getAll() { - Stream<Trace> entities = Trace.streamAll(); - return entities.map(TraceResource::toDto).toList(); - } - - /** - * Obtain trace information by identifier. - */ - @GET - @Path("{id}") - public org.opendc.web.proto.Trace get(@PathParam("id") String id) { - Trace trace = Trace.findById(id); - - if (trace == null) { - throw new WebApplicationException("Trace not found", 404); - } - - return toDto(trace); - } - - /** - * Convert a {@link Trace] entity into a {@link org.opendc.web.proto.Trace} DTO. - */ - public static org.opendc.web.proto.Trace toDto(Trace trace) { - return new org.opendc.web.proto.Trace(trace.id, trace.name, trace.type); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java deleted file mode 100644 index 345acdfe..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.error; - -import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; -import org.opendc.web.proto.ProtocolError; - -/** - * An [ExceptionMapper] for [MissingKotlinParameterException] thrown by Jackson. - */ -@Provider -public final class MissingKotlinParameterExceptionMapper implements ExceptionMapper<MissingKotlinParameterException> { - @Override - public Response toResponse(MissingKotlinParameterException exception) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new ProtocolError( - Response.Status.BAD_REQUEST.getStatusCode(), - "Field " + exception.getParameter().getName() + " is missing from body.")) - .type(MediaType.APPLICATION_JSON) - .build(); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java deleted file mode 100644 index e027e559..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.error; - -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; -import org.opendc.web.proto.ProtocolError; - -/** - * Helper class to transform a {@link WebApplicationException} into an JSON error response. - */ -@Provider -public final class WebApplicationExceptionMapper implements ExceptionMapper<WebApplicationException> { - @Override - public Response toResponse(WebApplicationException exception) { - int code = exception.getResponse().getStatus(); - - String message = exception.getMessage(); - if (message == null) { - message = "Unknown error"; - } - - return Response.status(code) - .entity(new ProtocolError(code, message)) - .type(MediaType.APPLICATION_JSON) - .build(); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java deleted file mode 100644 index 4dde8654..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.runner; - -import jakarta.annotation.security.RolesAllowed; -import jakarta.transaction.Transactional; -import jakarta.validation.Valid; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import java.util.List; -import org.opendc.web.proto.JobState; -import org.opendc.web.server.model.Job; -import org.opendc.web.server.service.JobService; - -/** - * A resource representing the available simulation jobs. - */ -@Produces("application/json") -@Path("/jobs") -@RolesAllowed("runner") -public final class JobResource { - /** - * The {@link JobService} for helping manage the job lifecycle. - */ - private final JobService jobService; - - /** - * Construct a {@link JobResource} instance. - * - * @param jobService The {@link JobService} for managing the job lifecycle. - */ - public JobResource(JobService jobService) { - this.jobService = jobService; - } - - /** - * Obtain all pending simulation jobs. - */ - @GET - public List<org.opendc.web.proto.runner.Job> queryPending() { - return Job.findByState(JobState.PENDING).list().stream() - .map(RunnerProtocol::toDto) - .toList(); - } - - /** - * Get a job by identifier. - */ - @GET - @Path("{job}") - public org.opendc.web.proto.runner.Job get(@PathParam("job") long id) { - Job job = Job.findById(id); - - if (job == null) { - throw new WebApplicationException("Job not found", 404); - } - - return RunnerProtocol.toDto(job); - } - - /** - * Atomically update the state of a job. - */ - @POST - @Path("{job}") - @Consumes("application/json") - @Transactional - public org.opendc.web.proto.runner.Job update( - @PathParam("job") long id, @Valid org.opendc.web.proto.runner.Job.Update update) { - Job job = Job.findById(id); - if (job == null) { - throw new WebApplicationException("Job not found", 404); - } - - try { - jobService.updateJob(job, update.getState(), update.getRuntime(), update.getResults()); - } catch (IllegalArgumentException e) { - throw new WebApplicationException(e, 400); - } catch (IllegalStateException e) { - throw new WebApplicationException(e, 409); - } - - return RunnerProtocol.toDto(job); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java deleted file mode 100644 index 6bf65d97..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.runner; - -import org.opendc.web.server.model.Job; -import org.opendc.web.server.model.Portfolio; -import org.opendc.web.server.model.Scenario; -import org.opendc.web.server.model.Topology; -import org.opendc.web.server.rest.BaseProtocol; - -/** - * DTO-conversions for the runner protocol. - */ -public final class RunnerProtocol { - /** - * Private constructor to prevent instantiation of class. - */ - private RunnerProtocol() {} - - /** - * Convert a {@link Job} into a runner-facing DTO. - */ - public static org.opendc.web.proto.runner.Job toDto(Job job) { - return new org.opendc.web.proto.runner.Job( - job.id, toDto(job.scenario), job.state, job.createdAt, job.updatedAt, job.runtime, job.results); - } - - /** - * Convert a {@link Scenario} into a runner-facing DTO. - */ - public static org.opendc.web.proto.runner.Scenario toDto(Scenario scenario) { - return new org.opendc.web.proto.runner.Scenario( - scenario.id, - scenario.number, - toDto(scenario.portfolio), - scenario.name, - BaseProtocol.toDto(scenario.workload), - toDto(scenario.topology), - scenario.phenomena, - scenario.schedulerName); - } - - /** - * Convert a {@link Portfolio} into a runner-facing DTO. - */ - public static org.opendc.web.proto.runner.Portfolio toDto(Portfolio portfolio) { - return new org.opendc.web.proto.runner.Portfolio( - portfolio.id, portfolio.number, portfolio.name, portfolio.targets); - } - - /** - * Convert a {@link Topology} into a runner-facing DTO. - */ - public static org.opendc.web.proto.runner.Topology toDto(Topology topology) { - return new org.opendc.web.proto.runner.Topology( - topology.id, topology.number, topology.name, topology.rooms, topology.createdAt, topology.updatedAt); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java deleted file mode 100644 index 2a3a40f4..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.user; - -import io.quarkus.security.identity.SecurityIdentity; -import jakarta.annotation.security.RolesAllowed; -import jakarta.transaction.Transactional; -import jakarta.validation.Valid; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import java.time.Instant; -import java.util.List; -import org.opendc.web.server.model.Portfolio; -import org.opendc.web.server.model.ProjectAuthorization; - -/** - * A resource representing the portfolios of a project. - */ -@Produces("application/json") -@Path("/projects/{project}/portfolios") -@RolesAllowed("openid") -public final class PortfolioResource { - /** - * The identity of the current user. - */ - private final SecurityIdentity identity; - - /** - * Construct a {@link PortfolioResource}. - * - * @param identity The {@link SecurityIdentity} of the current user. - */ - public PortfolioResource(SecurityIdentity identity) { - this.identity = identity; - } - - /** - * Get all portfolios that belong to the specified project. - */ - @GET - public List<org.opendc.web.proto.user.Portfolio> getAll(@PathParam("project") long projectId) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - return List.of(); - } - - return Portfolio.findByProject(projectId).list().stream() - .map((p) -> UserProtocol.toDto(p, auth)) - .toList(); - } - - /** - * Create a portfolio for this project. - */ - @POST - @Transactional - @Consumes("application/json") - public org.opendc.web.proto.user.Portfolio create( - @PathParam("project") long projectId, @Valid org.opendc.web.proto.user.Portfolio.Create request) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Project not found", 404); - } else if (!auth.canEdit()) { - throw new WebApplicationException("Not permitted to edit project", 403); - } - - var now = Instant.now(); - var project = auth.project; - int number = project.allocatePortfolio(now); - - Portfolio portfolio = new Portfolio(project, number, request.getName(), request.getTargets()); - - project.portfolios.add(portfolio); - portfolio.persist(); - - return UserProtocol.toDto(portfolio, auth); - } - - /** - * Obtain a portfolio by its identifier. - */ - @GET - @Path("{portfolio}") - public org.opendc.web.proto.user.Portfolio get( - @PathParam("project") long projectId, @PathParam("portfolio") int number) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Portfolio not found", 404); - } - - Portfolio portfolio = Portfolio.findByProject(projectId, number); - - if (portfolio == null) { - throw new WebApplicationException("Portfolio not found", 404); - } - - return UserProtocol.toDto(portfolio, auth); - } - - /** - * Delete a portfolio. - */ - @DELETE - @Path("{portfolio}") - @Transactional - public org.opendc.web.proto.user.Portfolio delete( - @PathParam("project") long projectId, @PathParam("portfolio") int number) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Portfolio not found", 404); - } else if (!auth.canEdit()) { - throw new WebApplicationException("Not permitted to edit project", 403); - } - - Portfolio entity = Portfolio.findByProject(projectId, number); - if (entity == null) { - throw new WebApplicationException("Portfolio not found", 404); - } - - entity.delete(); - return UserProtocol.toDto(entity, auth); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java deleted file mode 100644 index 789808c8..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.user; - -import io.quarkus.security.identity.SecurityIdentity; -import jakarta.annotation.security.RolesAllowed; -import jakarta.transaction.Transactional; -import jakarta.validation.Valid; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import java.time.Instant; -import java.util.List; -import org.opendc.web.proto.JobState; -import org.opendc.web.server.model.Job; -import org.opendc.web.server.model.Portfolio; -import org.opendc.web.server.model.ProjectAuthorization; -import org.opendc.web.server.model.Scenario; -import org.opendc.web.server.model.Topology; -import org.opendc.web.server.model.Trace; -import org.opendc.web.server.model.Workload; -import org.opendc.web.server.service.UserAccountingService; - -/** - * A resource representing the scenarios of a portfolio. - */ -@Path("/projects/{project}/portfolios/{portfolio}/scenarios") -@RolesAllowed("openid") -@Produces("application/json") -public final class PortfolioScenarioResource { - /** - * The service for managing the user accounting. - */ - private final UserAccountingService accountingService; - - /** - * The identity of the current user. - */ - private final SecurityIdentity identity; - - /** - * Construct a {@link PortfolioScenarioResource}. - * - * @param accountingService The {@link UserAccountingService} instance to use. - * @param identity The {@link SecurityIdentity} of the current user. - */ - public PortfolioScenarioResource(UserAccountingService accountingService, SecurityIdentity identity) { - this.accountingService = accountingService; - this.identity = identity; - } - - /** - * Get all scenarios that belong to the specified portfolio. - */ - @GET - public List<org.opendc.web.proto.user.Scenario> get( - @PathParam("project") long projectId, @PathParam("portfolio") int portfolioNumber) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - return List.of(); - } - - return org.opendc.web.server.model.Scenario.findByPortfolio(projectId, portfolioNumber).list().stream() - .map((s) -> UserProtocol.toDto(s, auth)) - .toList(); - } - - /** - * Create a scenario for this portfolio. - */ - @POST - @Transactional - @Consumes("application/json") - public org.opendc.web.proto.user.Scenario create( - @PathParam("project") long projectId, - @PathParam("portfolio") int portfolioNumber, - @Valid org.opendc.web.proto.user.Scenario.Create request) { - // User must have access to project - String userId = identity.getPrincipal().getName(); - ProjectAuthorization auth = ProjectAuthorization.findByUser(userId, projectId); - - if (auth == null) { - throw new WebApplicationException("Portfolio not found", 404); - } else if (!auth.canEdit()) { - throw new WebApplicationException("Not permitted to edit project", 403); - } - - Portfolio portfolio = Portfolio.findByProject(projectId, portfolioNumber); - - if (portfolio == null) { - throw new WebApplicationException("Portfolio not found", 404); - } - - Topology topology = Topology.findByProject(projectId, (int) request.getTopology()); - if (topology == null) { - throw new WebApplicationException("Referred topology does not exist", 400); - } - - Trace trace = Trace.findById(request.getWorkload().getTrace()); - if (trace == null) { - throw new WebApplicationException("Referred trace does not exist", 400); - } - - var now = Instant.now(); - var project = auth.project; - int number = project.allocateScenario(now); - - Scenario scenario = new Scenario( - project, - portfolio, - number, - request.getName(), - new Workload(trace, request.getWorkload().getSamplingFraction()), - topology, - request.getPhenomena(), - request.getSchedulerName()); - scenario.persist(); - - Job job = new Job(scenario, userId, now, portfolio.targets.getRepeats()); - job.persist(); - - // Fail the job if there is not enough budget for the simulation - if (!accountingService.hasSimulationBudget(userId)) { - job.state = JobState.FAILED; - } - - scenario.jobs.add(job); - portfolio.scenarios.add(scenario); - - return UserProtocol.toDto(scenario, auth); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java deleted file mode 100644 index ae1c959e..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.user; - -import io.quarkus.security.identity.SecurityIdentity; -import jakarta.annotation.security.RolesAllowed; -import jakarta.transaction.Transactional; -import jakarta.validation.Valid; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import java.time.Instant; -import java.util.List; -import org.opendc.web.proto.user.ProjectRole; -import org.opendc.web.server.model.Project; -import org.opendc.web.server.model.ProjectAuthorization; - -/** - * A resource representing the created projects. - */ -@Produces("application/json") -@Path("/projects") -@RolesAllowed("openid") -public final class ProjectResource { - /** - * The identity of the current user. - */ - private final SecurityIdentity identity; - - /** - * Construct a {@link ProjectResource}. - * - * @param identity The {@link SecurityIdentity} of the current user. - */ - public ProjectResource(SecurityIdentity identity) { - this.identity = identity; - } - - /** - * Obtain all the projects of the current user. - */ - @GET - public List<org.opendc.web.proto.user.Project> getAll() { - return ProjectAuthorization.findByUser(identity.getPrincipal().getName()).list().stream() - .map(UserProtocol::toDto) - .toList(); - } - - /** - * Create a new project for the current user. - */ - @POST - @Transactional - @Consumes("application/json") - public org.opendc.web.proto.user.Project create(@Valid org.opendc.web.proto.user.Project.Create request) { - Instant now = Instant.now(); - Project entity = new Project(request.getName(), now); - entity.persist(); - - ProjectAuthorization authorization = - new ProjectAuthorization(entity, identity.getPrincipal().getName(), ProjectRole.OWNER); - - entity.authorizations.add(authorization); - authorization.persist(); - - return UserProtocol.toDto(authorization); - } - - /** - * Obtain a single project by its identifier. - */ - @GET - @Path("{project}") - public org.opendc.web.proto.user.Project get(@PathParam("project") long project_id) { - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), project_id); - - if (auth == null) { - throw new WebApplicationException("Project not found", 404); - } - - return UserProtocol.toDto(auth); - } - - /** - * Delete a project. - */ - @DELETE - @Path("{project}") - @Transactional - public org.opendc.web.proto.user.Project delete(@PathParam("project") long id) { - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), id); - - if (auth == null) { - throw new WebApplicationException("Project not found", 404); - } else if (!auth.canDelete()) { - throw new WebApplicationException("Not allowed to delete project", 403); - } - - auth.project.updatedAt = Instant.now(); - org.opendc.web.proto.user.Project project = UserProtocol.toDto(auth); - auth.project.delete(); - return project; - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java deleted file mode 100644 index bb3eb89b..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.user; - -import io.quarkus.security.identity.SecurityIdentity; -import jakarta.annotation.security.RolesAllowed; -import jakarta.transaction.Transactional; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import java.util.List; -import org.opendc.web.server.model.ProjectAuthorization; -import org.opendc.web.server.model.Scenario; - -/** - * A resource representing the scenarios of a portfolio. - */ -@Produces("application/json") -@Path("/projects/{project}/scenarios") -@RolesAllowed("openid") -public final class ScenarioResource { - /** - * The identity of the current user. - */ - private final SecurityIdentity identity; - - /** - * Construct a {@link ScenarioResource}. - * - * @param identity The {@link SecurityIdentity} of the current user. - */ - public ScenarioResource(SecurityIdentity identity) { - this.identity = identity; - } - - /** - * Obtain the scenarios belonging to a project. - */ - @GET - public List<org.opendc.web.proto.user.Scenario> getAll(@PathParam("project") long projectId) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Project not found", 404); - } - - return Scenario.findByProject(projectId).list().stream() - .map((s) -> UserProtocol.toDto(s, auth)) - .toList(); - } - - /** - * Obtain a scenario by its identifier. - */ - @GET - @Path("{scenario}") - public org.opendc.web.proto.user.Scenario get( - @PathParam("project") long projectId, @PathParam("scenario") int number) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Project not found", 404); - } - - Scenario scenario = Scenario.findByProject(projectId, number); - - if (scenario == null) { - throw new WebApplicationException("Scenario not found", 404); - } - - return UserProtocol.toDto(scenario, auth); - } - - /** - * Delete a scenario. - */ - @DELETE - @Path("{scenario}") - @Transactional - public org.opendc.web.proto.user.Scenario delete( - @PathParam("project") long projectId, @PathParam("scenario") int number) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Project not found", 404); - } else if (!auth.canEdit()) { - throw new WebApplicationException("Not permitted to edit project", 403); - } - - Scenario entity = Scenario.findByProject(projectId, number); - if (entity == null) { - throw new WebApplicationException("Scenario not found", 404); - } - - entity.delete(); - return UserProtocol.toDto(entity, auth); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java deleted file mode 100644 index b8c542d3..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.user; - -import io.quarkus.hibernate.orm.panache.Panache; -import io.quarkus.security.identity.SecurityIdentity; -import jakarta.annotation.security.RolesAllowed; -import jakarta.persistence.PersistenceException; -import jakarta.transaction.Transactional; -import jakarta.validation.Valid; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import java.time.Instant; -import java.util.List; -import org.opendc.web.server.model.Project; -import org.opendc.web.server.model.ProjectAuthorization; -import org.opendc.web.server.model.Topology; - -/** - * A resource representing the constructed datacenter topologies. - */ -@Produces("application/json") -@Path("/projects/{project}/topologies") -@RolesAllowed("openid") -public final class TopologyResource { - /** - * The identity of the current user. - */ - private final SecurityIdentity identity; - - /** - * Construct a {@link TopologyResource}. - * - * @param identity The {@link SecurityIdentity} of the current user. - */ - public TopologyResource(SecurityIdentity identity) { - this.identity = identity; - } - - /** - * Get all topologies that belong to the specified project. - */ - @GET - public List<org.opendc.web.proto.user.Topology> getAll(@PathParam("project") long projectId) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - return List.of(); - } - - return Topology.findByProject(projectId).list().stream() - .map((t) -> UserProtocol.toDto(t, auth)) - .toList(); - } - - /** - * Create a topology for this project. - */ - @POST - @Consumes("application/json") - @Transactional - public org.opendc.web.proto.user.Topology create( - @PathParam("project") long projectId, @Valid org.opendc.web.proto.user.Topology.Create request) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Topology not found", 404); - } else if (!auth.canEdit()) { - throw new WebApplicationException("Not permitted to edit project", 403); - } - - Instant now = Instant.now(); - Project project = auth.project; - int number = project.allocateTopology(now); - - Topology topology = new Topology(project, number, request.getName(), now, request.getRooms()); - - project.topologies.add(topology); - topology.persist(); - - return UserProtocol.toDto(topology, auth); - } - - /** - * Obtain a topology by its number. - */ - @GET - @Path("{topology}") - public org.opendc.web.proto.user.Topology get( - @PathParam("project") long projectId, @PathParam("topology") int number) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Topology not found", 404); - } - - Topology topology = Topology.findByProject(projectId, number); - - if (topology == null) { - throw new WebApplicationException("Topology not found", 404); - } - - return UserProtocol.toDto(topology, auth); - } - - /** - * Update the specified topology by its number. - */ - @PUT - @Path("{topology}") - @Consumes("application/json") - @Transactional - public org.opendc.web.proto.user.Topology update( - @PathParam("project") long projectId, - @PathParam("topology") int number, - @Valid org.opendc.web.proto.user.Topology.Update request) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Topology not found", 404); - } else if (!auth.canEdit()) { - throw new WebApplicationException("Not permitted to edit project", 403); - } - - Topology entity = Topology.findByProject(projectId, number); - - if (entity == null) { - throw new WebApplicationException("Topology not found", 404); - } - - entity.updatedAt = Instant.now(); - entity.rooms = request.getRooms(); - - return UserProtocol.toDto(entity, auth); - } - - /** - * Delete the specified topology. - */ - @Path("{topology}") - @DELETE - @Transactional - public org.opendc.web.proto.user.Topology delete( - @PathParam("project") long projectId, @PathParam("topology") int number) { - // User must have access to project - ProjectAuthorization auth = - ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId); - - if (auth == null) { - throw new WebApplicationException("Topology not found", 404); - } else if (!auth.canEdit()) { - throw new WebApplicationException("Not permitted to edit project", 403); - } - - Topology entity = Topology.findByProject(projectId, number); - - if (entity == null) { - throw new WebApplicationException("Topology not found", 404); - } - - entity.updatedAt = Instant.now(); - entity.delete(); - - try { - // Flush the results, so we can check whether the constraints are not violated - Panache.flush(); - } catch (PersistenceException e) { - throw new WebApplicationException("Topology is still in use", 403); - } - - return UserProtocol.toDto(entity, auth); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java deleted file mode 100644 index 8196a9d6..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.user; - -import org.opendc.web.server.model.Job; -import org.opendc.web.server.model.Portfolio; -import org.opendc.web.server.model.Project; -import org.opendc.web.server.model.ProjectAuthorization; -import org.opendc.web.server.model.Scenario; -import org.opendc.web.server.model.Topology; -import org.opendc.web.server.rest.BaseProtocol; - -/** - * DTO-conversions for the user protocol. - */ -public final class UserProtocol { - /** - * Private constructor to prevent instantiation of class. - */ - private UserProtocol() {} - - /** - * Convert a {@link ProjectAuthorization} entity into a {@link Project} DTO. - */ - public static org.opendc.web.proto.user.Project toDto(ProjectAuthorization auth) { - Project project = auth.project; - return new org.opendc.web.proto.user.Project( - project.id, project.name, project.createdAt, project.updatedAt, auth.role); - } - - /** - * Convert a {@link Portfolio} entity into a {@link org.opendc.web.proto.user.Portfolio} DTO. - */ - public static org.opendc.web.proto.user.Portfolio toDto(Portfolio portfolio, ProjectAuthorization auth) { - return new org.opendc.web.proto.user.Portfolio( - portfolio.id, - portfolio.number, - toDto(auth), - portfolio.name, - portfolio.targets, - portfolio.scenarios.stream().map(UserProtocol::toSummaryDto).toList()); - } - - /** - * Convert a {@link Portfolio} entity into a {@link org.opendc.web.proto.user.Portfolio.Summary} DTO. - */ - public static org.opendc.web.proto.user.Portfolio.Summary toSummaryDto(Portfolio portfolio) { - return new org.opendc.web.proto.user.Portfolio.Summary( - portfolio.id, portfolio.number, portfolio.name, portfolio.targets); - } - - /** - * Convert a {@link Topology} entity into a {@link org.opendc.web.proto.user.Topology} DTO. - */ - public static org.opendc.web.proto.user.Topology toDto(Topology topology, ProjectAuthorization auth) { - return new org.opendc.web.proto.user.Topology( - topology.id, - topology.number, - toDto(auth), - topology.name, - topology.rooms, - topology.createdAt, - topology.updatedAt); - } - - /** - * Convert a {@link Topology} entity into a {@link org.opendc.web.proto.user.Topology.Summary} DTO. - */ - public static org.opendc.web.proto.user.Topology.Summary toSummaryDto(Topology topology) { - return new org.opendc.web.proto.user.Topology.Summary( - topology.id, topology.number, topology.name, topology.createdAt, topology.updatedAt); - } - - /** - * Convert a {@link Scenario} entity into a {@link org.opendc.web.proto.user.Scenario} DTO. - */ - public static org.opendc.web.proto.user.Scenario toDto(Scenario scenario, ProjectAuthorization auth) { - return new org.opendc.web.proto.user.Scenario( - scenario.id, - scenario.number, - toDto(auth), - toSummaryDto(scenario.portfolio), - scenario.name, - BaseProtocol.toDto(scenario.workload), - toSummaryDto(scenario.topology), - scenario.phenomena, - scenario.schedulerName, - scenario.jobs.stream().map(UserProtocol::toDto).toList()); - } - - /** - * Convert a {@link Scenario} entity into a {@link org.opendc.web.proto.user.Scenario.Summary} DTO. - */ - public static org.opendc.web.proto.user.Scenario.Summary toSummaryDto(Scenario scenario) { - return new org.opendc.web.proto.user.Scenario.Summary( - scenario.id, - scenario.number, - scenario.name, - BaseProtocol.toDto(scenario.workload), - toSummaryDto(scenario.topology), - scenario.phenomena, - scenario.schedulerName, - scenario.jobs.stream().map(UserProtocol::toDto).toList()); - } - - /** - * Convert a {@link Job} entity into a {@link org.opendc.web.proto.user.Job} DTO. - */ - public static org.opendc.web.proto.user.Job toDto(Job job) { - return new org.opendc.web.proto.user.Job(job.id, job.state, job.createdAt, job.updatedAt, job.results); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java deleted file mode 100644 index c8cda2b7..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.rest.user; - -import io.quarkus.security.identity.SecurityIdentity; -import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import org.opendc.web.proto.user.User; -import org.opendc.web.proto.user.UserAccounting; -import org.opendc.web.server.service.UserAccountingService; - -/** - * A resource representing the active user. - */ -@Produces("application/json") -@Path("/users") -@RolesAllowed("openid") -public final class UserResource { - /** - * The service for managing the user accounting. - */ - private final UserAccountingService accountingService; - - /** - * The identity of the current user. - */ - private final SecurityIdentity identity; - - /** - * Construct a {@link UserResource}. - * - * @param accountingService The {@link UserAccountingService} instance to use. - * @param identity The {@link SecurityIdentity} of the current user. - */ - public UserResource(UserAccountingService accountingService, SecurityIdentity identity) { - this.accountingService = accountingService; - this.identity = identity; - } - - /** - * Get the current active user data. - */ - @GET - @Path("me") - public User get() { - String userId = identity.getPrincipal().getName(); - UserAccounting accounting = accountingService.getAccounting(userId); - - return new User(userId, accounting); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java deleted file mode 100644 index 70933520..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.service; - -import jakarta.enterprise.context.ApplicationScoped; -import java.time.Instant; -import java.util.Map; -import org.opendc.web.proto.JobState; -import org.opendc.web.server.model.Job; - -/** - * A service for managing the lifecycle of a job and ensuring that the user does not consume - * too much simulation resources. - */ -@ApplicationScoped -public final class JobService { - /** - * The {@link UserAccountingService} responsible for accounting the simulation time of users. - */ - private final UserAccountingService accountingService; - - /** - * Construct a {@link JobService} instance. - * - * @param accountingService The {@link UserAccountingService} for accounting the simulation time of users. - */ - public JobService(UserAccountingService accountingService) { - this.accountingService = accountingService; - } - - /** - * Update the job state. - * - * @param job The {@link Job} to update. - * @param newState The new state to transition the job to. - * @param runtime The runtime (in seconds) consumed by the simulation jbo so far. - * @param results The results to attach to the job. - * @throws IllegalArgumentException if the state transition is invalid. - * @throws IllegalStateException if someone tries to update the job concurrently. - */ - public void updateJob(Job job, JobState newState, int runtime, Map<String, ?> results) { - JobState state = job.state; - - if (!job.canTransitionTo(newState)) { - throw new IllegalArgumentException("Invalid transition from %s to %s".formatted(state, newState)); - } - - Instant now = Instant.now(); - JobState nextState = newState; - int consumedBudget = Math.min(1, runtime - job.runtime); - - // Check whether the user still has any simulation budget left - if (accountingService.consumeSimulationBudget(job.createdBy, consumedBudget) && nextState == JobState.RUNNING) { - nextState = JobState.FAILED; // User has consumed all their budget; cancel the job - } - - if (!job.updateAtomically(nextState, now, runtime, results)) { - throw new IllegalStateException("Conflicting update"); - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java deleted file mode 100644 index 73fa2a3e..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.service; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.persistence.EntityExistsException; -import java.time.Duration; -import java.time.LocalDate; -import java.time.temporal.TemporalAdjusters; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.opendc.web.server.model.UserAccounting; - -/** - * Service to track the simulation budget of users. - */ -@ApplicationScoped -public final class UserAccountingService { - /** - * The default simulation budget for new users. - */ - private final Duration simulationBudget; - - /** - * Construct a {@link UserAccountingService} instance. - * - * @param simulationBudget The default simulation budget for new users. - */ - public UserAccountingService( - @ConfigProperty(name = "opendc.accounting.simulation-budget", defaultValue = "2000m") - Duration simulationBudget) { - this.simulationBudget = simulationBudget; - } - - /** - * Return the {@link org.opendc.web.proto.user.UserAccounting} object for the user with the - * specified <code>userId</code>. If the object does not exist in the database, a default value is constructed. - */ - public org.opendc.web.proto.user.UserAccounting getAccounting(String userId) { - UserAccounting accounting = UserAccounting.findByUser(userId); - if (accounting != null) { - return new org.opendc.web.proto.user.UserAccounting( - accounting.periodEnd, accounting.simulationTime, accounting.simulationTimeBudget); - } - - return new org.opendc.web.proto.user.UserAccounting( - getNextAccountingPeriod(LocalDate.now()), 0, (int) simulationBudget.toSeconds()); - } - - /** - * Determine whether the user with <code>userId</code> has any remaining simulation budget. - * - * @param userId The unique identifier of the user. - * @return <code>true</code> when the user still has budget left, <code>false</code> otherwise. - */ - public boolean hasSimulationBudget(String userId) { - UserAccounting accounting = UserAccounting.findByUser(userId); - if (accounting == null) { - return true; - } - return accounting.hasSimulationBudget(); - } - - /** - * Consume <code>seconds</code> from the simulation budget of the user with <code>userId</code>. - * - * @param userId The unique identifier of the user. - * @param seconds The seconds to consume from the simulation budget. - * @return <code>true</code> if the user has consumed his full budget or <code>false</code> if there is still budget - * remaining. - */ - public boolean consumeSimulationBudget(String userId, int seconds) { - LocalDate today = LocalDate.now(); - LocalDate nextAccountingPeriod = getNextAccountingPeriod(today); - - // We need to be careful to prevent conflicts in case of concurrency - // 1. First, we try to create the accounting object if it does not exist yet. This may fail if another instance - // creates the object concurrently. - // 2. Second, we check if the budget needs to be reset and try this atomically. - // 3. Finally, we atomically consume the budget from the object - // This is repeated three times in case there is a conflict - for (int i = 0; i < 3; i++) { - UserAccounting accounting = UserAccounting.findByUser(userId); - - if (accounting == null) { - try { - UserAccounting newAccounting = UserAccounting.create( - userId, nextAccountingPeriod, (int) simulationBudget.toSeconds(), seconds); - return !newAccounting.hasSimulationBudget(); - } catch (EntityExistsException e) { - // Conflict due to concurrency; retry - } - } else { - boolean success; - - if (!today.isBefore(accounting.periodEnd)) { - success = accounting.resetBudget(nextAccountingPeriod, seconds); - } else { - success = accounting.consumeBudget(seconds); - } - - if (success) { - return !accounting.hasSimulationBudget(); - } - } - } - - throw new IllegalStateException("Failed to allocate consume budget due to conflict"); - } - - /** - * Helper method to find next accounting period. - */ - private static LocalDate getNextAccountingPeriod(LocalDate today) { - return today.with(TemporalAdjusters.firstDayOfNextMonth()); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java deleted file mode 100644 index 103f868d..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java +++ /dev/null @@ -1,64 +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.web.server.util; - -import io.quarkus.arc.properties.IfBuildProperty; -import jakarta.ws.rs.container.ContainerRequestContext; -import jakarta.ws.rs.container.ContainerRequestFilter; -import jakarta.ws.rs.container.PreMatching; -import jakarta.ws.rs.core.SecurityContext; -import jakarta.ws.rs.ext.Provider; -import java.security.Principal; - -/** - * Helper class to disable security for the OpenDC web API when in development mode. - */ -@Provider -@PreMatching -@IfBuildProperty(name = "opendc.security.enabled", stringValue = "false") -public class DevSecurityOverrideFilter implements ContainerRequestFilter { - @Override - public void filter(ContainerRequestContext requestContext) { - requestContext.setSecurityContext(new SecurityContext() { - @Override - public Principal getUserPrincipal() { - return () -> "anon"; - } - - @Override - public boolean isUserInRole(String role) { - return true; - } - - @Override - public boolean isSecure() { - return false; - } - - @Override - public String getAuthenticationScheme() { - return "basic"; - } - }); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java deleted file mode 100644 index ff3ba1cd..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.util; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.module.kotlin.KotlinModule; -import io.quarkus.jackson.ObjectMapperCustomizer; -import jakarta.inject.Singleton; - -/** - * Helper class to register the Kotlin Jackson module. - */ -@Singleton -public final class KotlinModuleCustomizer implements ObjectMapperCustomizer { - @Override - public void customize(ObjectMapper objectMapper) { - objectMapper.registerModule(new KotlinModule.Builder().build()); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java deleted file mode 100644 index 60ca77e5..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023 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.web.server.util; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.hypersistence.utils.hibernate.type.util.ObjectMapperSupplier; -import io.quarkus.runtime.annotations.RegisterForReflection; -import jakarta.enterprise.inject.spi.CDI; - -/** - * A supplier for an {@link ObjectMapper} used by the Hypersistence utilities. - */ -@RegisterForReflection -public class QuarkusObjectMapperSupplier implements ObjectMapperSupplier { - @Override - public ObjectMapper get() { - return CDI.current().select(ObjectMapper.class).get(); - } -} diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java deleted file mode 100644 index 47d397f3..00000000 --- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java +++ /dev/null @@ -1,114 +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.web.server.util.runner; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.transaction.Transactional; -import java.util.Map; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.opendc.web.proto.JobState; -import org.opendc.web.runner.JobManager; -import org.opendc.web.server.model.Job; -import org.opendc.web.server.rest.runner.RunnerProtocol; -import org.opendc.web.server.service.JobService; - -/** - * Implementation of {@link JobManager} that interfaces directly with the database without overhead of the REST API. - */ -@ApplicationScoped -public class QuarkusJobManager implements JobManager { - /** - * The {@link JobService} used to manage the job's lifecycle. - */ - private final JobService jobService; - - /** - * Construct a {@link QuarkusJobManager}. - * - * @param jobService The {@link JobService} for managing the job's lifecycle. - */ - public QuarkusJobManager(JobService jobService) { - this.jobService = jobService; - } - - @Transactional - @Nullable - @Override - public org.opendc.web.proto.runner.Job findNext() { - var job = Job.findByState(JobState.PENDING).firstResult(); - if (job == null) { - return null; - } - - return RunnerProtocol.toDto(job); - } - - @Transactional - @Override - public boolean claim(long id) { - return updateState(id, JobState.CLAIMED, 0, null); - } - - @Transactional - @Override - public boolean heartbeat(long id, int runtime) { - return updateState(id, JobState.RUNNING, runtime, null); - } - - @Transactional - @Override - public void fail(long id, int runtime) { - updateState(id, JobState.FAILED, runtime, null); - } - - @Transactional - @Override - public void finish(long id, int runtime, @NotNull Map<String, ?> results) { - updateState(id, JobState.FINISHED, runtime, results); - } - - /** - * Helper method to update the state of a job. - * - * @param id The unique id of the job. - * @param newState The new state to transition to. - * @param runtime The runtime of the job. - * @param results The results of the job. - * @return <code>true</code> if the operation succeeded, <code>false</code> otherwise. - */ - private boolean updateState(long id, JobState newState, int runtime, Map<String, ?> results) { - Job job = Job.findById(id); - - if (job == null) { - return false; - } - - try { - jobService.updateJob(job, newState, runtime, results); - return true; - } catch (IllegalArgumentException | IllegalStateException e) { - return false; - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png b/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png Binary files differdeleted file mode 100644 index d743038b..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png +++ /dev/null diff --git a/opendc-web/opendc-web-server/src/main/resources/application-dev.properties b/opendc-web/opendc-web-server/src/main/resources/application-dev.properties deleted file mode 100644 index 5fbc4c04..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/application-dev.properties +++ /dev/null @@ -1,36 +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. - -# Datasource (H2) -quarkus.datasource.db-kind=h2 -quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json; - -# Hibernate -quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect -quarkus.flyway.clean-at-start=true - -# Disable authentication -opendc.security.enabled=false - -# Mount web UI at root and API at "/api" -quarkus.resteasy.path=/api - -# Swagger UI -quarkus.smallrye-openapi.servers=http://localhost:8080 diff --git a/opendc-web/opendc-web-server/src/main/resources/application-docker.properties b/opendc-web/opendc-web-server/src/main/resources/application-docker.properties deleted file mode 100644 index eae9ee1e..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/application-docker.properties +++ /dev/null @@ -1,49 +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. - -# Configuration for standalone Docker server distribution without web UI. - -# Datasource -quarkus.datasource.db-kind=postgresql -quarkus.datasource.username=${OPENDC_DB_USERNAME} -quarkus.datasource.password=${OPENDC_DB_PASSWORD} -quarkus.datasource.jdbc.url=${OPENDC_DB_URL} - -# Hibernate -quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL95Dialect - -# Disable OpenDC web UI -quarkus.opendc-ui.include=false - -# Security -opendc.security.enabled=true -quarkus.oidc.auth-server-url=https://${OPENDC_AUTH0_DOMAIN} -quarkus.oidc.client-id=${OPENDC_AUTH0_AUDIENCE} -quarkus.oidc.token.audience=${quarkus.oidc.client-id} -quarkus.oidc.roles.role-claim-path=scope - -# Swagger UI -quarkus.swagger-ui.oauth-client-id=${OPENDC_AUTH0_DOCS_CLIENT_ID:} -quarkus.swagger-ui.oauth-additional-query-string-params={"audience":"${OPENDC_AUTH0_AUDIENCE:https://api.opendc.org/v2/}"} - -quarkus.smallrye-openapi.security-scheme=oidc -quarkus.smallrye-openapi.security-scheme-name=Auth0 -quarkus.smallrye-openapi.oidc-open-id-connect-url=https://${OPENDC_AUTH0_DOMAIN:opendc.eu.auth0.com}/.well-known/openid-configuration -quarkus.smallrye-openapi.servers=https://api.opendc.org diff --git a/opendc-web/opendc-web-server/src/main/resources/application-prod.properties b/opendc-web/opendc-web-server/src/main/resources/application-prod.properties deleted file mode 100644 index fe997fc0..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/application-prod.properties +++ /dev/null @@ -1,36 +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. - -# Datasource (H2) -quarkus.datasource.db-kind=h2 -quarkus.datasource.jdbc.url=jdbc:h2:file:./data/opendc;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json; - -# Hibernate -quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect - -# Disable authentication -opendc.security.enabled=false -quarkus.oidc.enabled=${opendc.security.enabled} - -# Mount web UI at root and API at "/api" -quarkus.resteasy.path=/api - -# Swagger UI -quarkus.smallrye-openapi.servers=http://localhost:8080 diff --git a/opendc-web/opendc-web-server/src/main/resources/application-test.properties b/opendc-web/opendc-web-server/src/main/resources/application-test.properties deleted file mode 100644 index 4e3063e4..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/application-test.properties +++ /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. - -# Datasource configuration -quarkus.datasource.db-kind = h2 -quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json; - -quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect -quarkus.hibernate-orm.log.sql=true -quarkus.flyway.clean-at-start=true -quarkus.flyway.locations=db/migration,db/testing - -# Disable security -quarkus.oidc.enabled=false - -# Disable OpenAPI/Swagger -quarkus.smallrye-openapi.enable=false -quarkus.swagger-ui.enable=false - -# Disable OpenDC web UI and runner -quarkus.opendc-ui.include=false -quarkus.opendc-runner.include=false - -# Create new tables and fill them -quarkus.hibernate-orm.database.generation=drop-and-create -quarkus.hibernate-orm.sql-load-script=load_data.sql diff --git a/opendc-web/opendc-web-server/src/main/resources/application.properties b/opendc-web/opendc-web-server/src/main/resources/application.properties deleted file mode 100644 index 0f47db30..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/application.properties +++ /dev/null @@ -1,49 +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. - -# Enable CORS -quarkus.http.cors=true -quarkus.http.cors.origins=http://localhost:3000,https://opendc.org - -# Security -quarkus.oidc.enabled=${opendc.security.enabled} - -# Runner logging -quarkus.log.category."org.opendc".level=ERROR -quarkus.log.category."org.opendc.web".level=INFO -quarkus.log.category."org.apache".level=WARN - -# OpenAPI and Swagger -quarkus.smallrye-openapi.info-title=OpenDC REST API -%dev.quarkus.smallrye-openapi.info-title=OpenDC REST API (development) -quarkus.smallrye-openapi.info-version=2.1-rc1 -quarkus.smallrye-openapi.info-description=OpenDC is an open-source datacenter simulator for education, featuring real-time online collaboration, diverse simulation models, and detailed performance feedback statistics. -quarkus.smallrye-openapi.info-contact-email=opendc@atlarge-research.com -quarkus.smallrye-openapi.info-contact-name=OpenDC Support -quarkus.smallrye-openapi.info-contact-url=https://opendc.org -quarkus.smallrye-openapi.info-license-name=MIT -quarkus.smallrye-openapi.info-license-url=https://github.com/atlarge-research/opendc/blob/master/LICENSE.txt - -quarkus.swagger-ui.path=docs -quarkus.swagger-ui.always-include=true - -# Flyway database migrations -quarkus.flyway.baseline-on-migrate=true -quarkus.flyway.migrate-at-start=true diff --git a/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties b/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties deleted file mode 100644 index 451ce2d8..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties +++ /dev/null @@ -1 +0,0 @@ -hypersistence.utils.jackson.object.mapper=org.opendc.web.server.util.QuarkusObjectMapperSupplier diff --git a/opendc-web/opendc-web-server/src/main/resources/load_data.sql b/opendc-web/opendc-web-server/src/main/resources/load_data.sql deleted file mode 100644 index 72396cef..00000000 --- a/opendc-web/opendc-web-server/src/main/resources/load_data.sql +++ /dev/null @@ -1,124 +0,0 @@ - --- Insert data - -INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id) - VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 1', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 1); - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('OWNER', 1, 'test_user_1'); - --- Add test user 2 as a viewer for project 1 - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('VIEWER', 1, 'test_user_2'); - --- Add test user 3 as an editor for project 1 - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('EDITOR', 1, 'test_user_3'); - --- Create a project for test user 2 - -INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 2', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 2); - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('OWNER', 2, 'test_user_2'); - --- Create three projects for test user 3. User 3 has multiple projects to test getAll - -INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 3', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 3); - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('OWNER', 3, 'test_user_3'); - -INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 4', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 4); - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('OWNER', 4, 'test_user_3'); - -INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 5', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 5); - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('OWNER', 5, 'test_user_3'); - --- Project to delete - -INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project Delete', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 6); - -INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name) -VALUES ('OWNER', 6, 'test_user_1'); - --- -------------------------------------------------------------------------------- --- PortFolios --- -------------------------------------------------------------------------------- - --- Add Portfolio to project 1 -INSERT INTO PORTFOLIO (name, number, project_id, targets, id) -VALUES ('Test PortFolio Base', 1, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 1); - -INSERT INTO PORTFOLIO (name, number, project_id, targets, id) -VALUES ('Test PortFolio Delete', 2, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 2); - -INSERT INTO PORTFOLIO (name, number, project_id, targets, id) -VALUES ('Test PortFolio DeleteEditor', 3, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 3); - -UPDATE Project p -SET p.portfolios_created = 3, p.updated_at = '2024-03-01T15:31:41.579969Z' -WHERE p.id = 1; - --- -------------------------------------------------------------------------------- --- Topologies --- -------------------------------------------------------------------------------- - -INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testUpdate', 1, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 1); - -INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDeleteAsEditor', 2, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 2); - -INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDelete', 3, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 3); - -INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id) -VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDeleteUsed', 4, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 4); - -UPDATE Project p -SET p.topologies_created = 4, p.updated_at = '2024-03-01T15:31:41.579969Z' -WHERE p.id = 1; - --- -------------------------------------------------------------------------------- --- Traces --- -------------------------------------------------------------------------------- - -INSERT INTO TRACE (id, name, type) -VALUES ('bitbrains-small', 'Bitbrains Small', 'small'); - --- -------------------------------------------------------------------------------- --- Scenario --- -------------------------------------------------------------------------------- - -INSERT INTO SCENARIO (name, number, phenomena, portfolio_id, project_id, scheduler_name, topology_id, sampling_fraction, trace_id, id) -VALUES ('Test Scenario testDelete', 1, '{"failures": false, "interference": false}' FORMAT JSON, 1, 1, 'test', 1, 1.0, 'bitbrains-small', 1); - -INSERT INTO SCENARIO (name, number, phenomena, portfolio_id, project_id, scheduler_name, topology_id, sampling_fraction, trace_id, id) -VALUES ('Test Scenario testDeleteUsed', 2, '{"failures": false, "interference": false}' FORMAT JSON, 1, 1, 'test', 4, 1.0, 'bitbrains-small', 2); - - -UPDATE Project p -SET p.scenarios_created = 2, p.updated_at = '2024-03-01T15:31:41.579969Z' -WHERE p.id = 1; - --- -------------------------------------------------------------------------------- --- Job --- -------------------------------------------------------------------------------- - -INSERT INTO JOB (scenario_id, created_by, created_at, repeats, updated_at, state, runtime, results, id) -VALUES (1, 'test_user_1', '2024-03-01T15:31:41.579969Z', 1, '2024-03-01T15:31:41.579969Z', 'PENDING', 1, '{}' FORMAT JSON, 1); - -INSERT INTO JOB (scenario_id, created_by, created_at, repeats, updated_at, state, runtime, results, id) -VALUES (1, 'test_user_1', '2024-03-01T15:31:41.579969Z', 1, '2024-03-01T15:31:41.579969Z', 'PENDING', 1, '{}' FORMAT JSON, 2); |
