diff options
31 files changed, 551 insertions, 45 deletions
diff --git a/build.gradle.kts b/build.gradle.kts index ea1a256a..87a338b9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,6 +27,5 @@ plugins { } allprojects { - group = "org.opendc" version = "2.1-rc1" } diff --git a/opendc-common/build.gradle.kts b/opendc-common/build.gradle.kts index 7da937c4..f1c22f61 100644 --- a/opendc-common/build.gradle.kts +++ b/opendc-common/build.gradle.kts @@ -20,6 +20,7 @@ * SOFTWARE. */ +group = "org.opendc" description = "Common functionality used across OpenDC modules" /* Build configuration */ diff --git a/opendc-trace/opendc-trace-parquet/build.gradle.kts b/opendc-trace/opendc-trace-parquet/build.gradle.kts index 794dd655..9b1e1273 100644 --- a/opendc-trace/opendc-trace-parquet/build.gradle.kts +++ b/opendc-trace/opendc-trace-parquet/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { exclude(group = "org.apache.htrace") exclude(group = "commons-cli") exclude(group = "javax.servlet") + exclude(group = "javax.servlet.jsp") exclude(group = "org.eclipse.jetty") exclude(group = "com.sun.jersey") exclude(group = "com.jcraft") diff --git a/opendc-web/opendc-web-api/build.gradle.kts b/opendc-web/opendc-web-api/build.gradle.kts index 5ef6009f..89b8273c 100644 --- a/opendc-web/opendc-web-api/build.gradle.kts +++ b/opendc-web/opendc-web-api/build.gradle.kts @@ -25,14 +25,17 @@ description = "REST API for the OpenDC website" /* Build configuration */ plugins { `quarkus-conventions` + distribution } dependencies { implementation(enforcedPlatform(libs.quarkus.bom)) implementation(projects.opendcWeb.opendcWebProto) - compileOnly(projects.opendcWeb.opendcWebUiQuarkus.deployment) /* Temporary fix for Quarkus/Gradle issues */ - implementation(projects.opendcWeb.opendcWebUiQuarkus.runtime) + compileOnly(projects.opendcWeb.opendcWebUiQuarkusDeployment) /* Temporary fix for Quarkus/Gradle issues */ + compileOnly(projects.opendcWeb.opendcWebRunnerQuarkusDeployment) + implementation(projects.opendcWeb.opendcWebUiQuarkus) + implementation(projects.opendcWeb.opendcWebRunnerQuarkus) implementation(libs.quarkus.kotlin) implementation(libs.quarkus.resteasy.core) @@ -56,3 +59,30 @@ dependencies { testImplementation(libs.quarkus.test.security) testImplementation(libs.quarkus.jdbc.h2) } + +val createStartScripts by tasks.creating(CreateStartScripts::class) { + applicationName = "opendc-server" + mainClass.set("io.quarkus.bootstrap.runner.QuarkusEntryPoint") + classpath = files("lib/quarkus-run.jar") + outputDir = project.buildDir.resolve("scripts") +} + +distributions { + create("server") { + distributionBaseName.set("opendc-server") + + contents { + from("../../LICENSE.txt") + from("config") { + into("config") + } + + from(createStartScripts) { + into("bin") + } + from(tasks.quarkusBuild) { + into("lib") + } + } + } +} diff --git a/opendc-web/opendc-web-api/config/application.properties b/opendc-web/opendc-web-api/config/application.properties new file mode 100644 index 00000000..30eaaef9 --- /dev/null +++ b/opendc-web/opendc-web-api/config/application.properties @@ -0,0 +1 @@ +# Custom server properties diff --git a/opendc-web/opendc-web-api/src/main/resources/application-prod.properties b/opendc-web/opendc-web-api/src/main/resources/application-prod.properties index 8f523d76..cebcdaab 100644 --- a/opendc-web/opendc-web-api/src/main/resources/application-prod.properties +++ b/opendc-web/opendc-web-api/src/main/resources/application-prod.properties @@ -28,5 +28,6 @@ quarkus.datasource.jdbc.url=${OPENDC_DB_URL} quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL95Dialect quarkus.hibernate-orm.database.generation=validate -# Disable OpenDC web UI +# Disable OpenDC web UI and runner quarkus.opendc-ui.include=false +quarkus.opendc-runner.include=false diff --git a/opendc-web/opendc-web-api/src/main/resources/application-test.properties b/opendc-web/opendc-web-api/src/main/resources/application-test.properties index ea07de6e..10197119 100644 --- a/opendc-web/opendc-web-api/src/main/resources/application-test.properties +++ b/opendc-web/opendc-web-api/src/main/resources/application-test.properties @@ -35,5 +35,6 @@ quarkus.smallrye-openapi.enable=false quarkus.swagger-ui.enable=false quarkus.smallrye-openapi.oidc-open-id-connect-url= -# Disable OpenDC web UI +# Disable OpenDC web UI and runner quarkus.opendc-ui.include=false +quarkus.opendc-runner.include=false diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt index 33f2b41e..a34c7864 100644 --- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt +++ b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt @@ -39,7 +39,7 @@ public class OpenDCClient(client: TransportClient) { * @param baseUrl The base url of the API. * @param auth Helper class for managing authentication. */ - public constructor(baseUrl: URI, auth: AuthController) : this(HttpTransportClient(baseUrl, auth)) + public constructor(baseUrl: URI, auth: AuthController? = null) : this(HttpTransportClient(baseUrl, auth)) /** * A resource for the available projects. diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt index a3cff6c3..e2112b8c 100644 --- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt +++ b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt @@ -40,7 +40,7 @@ public class OpenDCRunnerClient(client: TransportClient) { * @param baseUrl The base url of the API. * @param auth Helper class for managing authentication. */ - public constructor(baseUrl: URI, auth: AuthController) : this(HttpTransportClient(baseUrl, auth)) + public constructor(baseUrl: URI, auth: AuthController? = null) : this(HttpTransportClient(baseUrl, auth)) /** * A resource for the available simulation jobs. diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt index 03b3945f..e407380b 100644 --- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt +++ b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt @@ -42,7 +42,7 @@ import java.nio.file.Paths */ public class HttpTransportClient( private val baseUrl: URI, - private val auth: AuthController, + private val auth: AuthController?, private val client: HttpClient = HttpClient.newHttpClient() ) : TransportClient { /** @@ -58,15 +58,20 @@ public class HttpTransportClient( override fun <T> get(path: String, targetType: TypeReference<T>): T? { val request = HttpRequest.newBuilder(buildUri(path)) .GET() - .also { auth.injectToken(it) } + .also { auth?.injectToken(it) } .build() val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()) return when (val code = response.statusCode()) { in 200..299 -> mapper.readValue(response.body(), targetType) 401 -> { - auth.refreshToken() - get(path, targetType) + val auth = auth + if (auth != null) { + auth.refreshToken() + get(path, targetType) + } else { + throw IllegalStateException("Authorization required") + } } 404 -> null else -> throw IllegalStateException("Invalid response $code") @@ -80,15 +85,20 @@ public class HttpTransportClient( val request = HttpRequest.newBuilder(buildUri(path)) .POST(HttpRequest.BodyPublishers.ofByteArray(mapper.writeValueAsBytes(body))) .header("Content-Type", "application/json") - .also { auth.injectToken(it) } + .also { auth?.injectToken(it) } .build() val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()) return when (val code = response.statusCode()) { in 200..299 -> mapper.readValue(response.body(), targetType) 401 -> { - auth.refreshToken() - post(path, body, targetType) + val auth = auth + if (auth != null) { + auth.refreshToken() + post(path, body, targetType) + } else { + throw IllegalStateException("Authorization required") + } } 404 -> null else -> throw IllegalStateException("Invalid response $code") @@ -102,15 +112,20 @@ public class HttpTransportClient( val request = HttpRequest.newBuilder(buildUri(path)) .PUT(HttpRequest.BodyPublishers.ofByteArray(mapper.writeValueAsBytes(body))) .header("Content-Type", "application/json") - .also { auth.injectToken(it) } + .also { auth?.injectToken(it) } .build() val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()) return when (val code = response.statusCode()) { in 200..299 -> mapper.readValue(response.body(), targetType) 401 -> { - auth.refreshToken() - put(path, body, targetType) + val auth = auth + if (auth != null) { + auth.refreshToken() + put(path, body, targetType) + } else { + throw IllegalStateException("Authorization required") + } } 404 -> null else -> throw IllegalStateException("Invalid response $code") @@ -123,15 +138,20 @@ public class HttpTransportClient( override fun <T> delete(path: String, targetType: TypeReference<T>): T? { val request = HttpRequest.newBuilder(buildUri(path)) .DELETE() - .also { auth.injectToken(it) } + .also { auth?.injectToken(it) } .build() val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()) return when (val code = response.statusCode()) { in 200..299 -> mapper.readValue(response.body(), targetType) 401 -> { - auth.refreshToken() - delete(path, targetType) + val auth = auth + if (auth != null) { + auth.refreshToken() + delete(path, targetType) + } else { + throw IllegalStateException("Authorization required") + } } 404 -> null else -> throw IllegalStateException("Invalid response $code") diff --git a/opendc-web/opendc-web-ui-quarkus/runtime/build.gradle.kts b/opendc-web/opendc-web-runner-quarkus-deployment/build.gradle.kts index f4131f0b..24f667cf 100644 --- a/opendc-web/opendc-web-ui-quarkus/runtime/build.gradle.kts +++ b/opendc-web/opendc-web-runner-quarkus-deployment/build.gradle.kts @@ -20,17 +20,16 @@ * SOFTWARE. */ -description = "Quarkus extension for serving OpenDC web interface" +description = "Quarkus extension for the OpenDC experiment runner" +/* Build configuration */ plugins { `java-library-conventions` - id("io.quarkus.extension") } dependencies { - implementation(enforcedPlatform(libs.quarkus.bom)) + implementation(projects.opendcWeb.opendcWebRunnerQuarkus) - implementation(libs.quarkus.core.runtime) - implementation(libs.quarkus.vertx.http.runtime) - implementation(libs.quarkus.arc.runtime) + implementation(platform(libs.quarkus.bom)) + implementation(libs.quarkus.core.deployment) } diff --git a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerBuildItem.java b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerBuildItem.java new file mode 100644 index 00000000..3be15ee3 --- /dev/null +++ b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerBuildItem.java @@ -0,0 +1,42 @@ +/* + * 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.runner.deployment; + +import io.quarkus.builder.item.SimpleBuildItem; +import io.quarkus.runtime.RuntimeValue; +import org.opendc.web.runner.OpenDCRunner; + +/** + * A {@link SimpleBuildItem} that produces an {@link OpenDCRunner} instance. + */ +public final class OpenDCRunnerBuildItem extends SimpleBuildItem { + private final RuntimeValue<OpenDCRunner> runner; + + public OpenDCRunnerBuildItem(RuntimeValue<OpenDCRunner> runner) { + this.runner = runner; + } + + public RuntimeValue<OpenDCRunner> getRunner() { + return runner; + } +} diff --git a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerConfig.java b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerConfig.java new file mode 100644 index 00000000..ccbc5e19 --- /dev/null +++ b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerConfig.java @@ -0,0 +1,38 @@ +/* + * 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.runner.deployment; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigRoot; + +/** + * Build-time configuration for the OpenDC web runner extension. + */ +@ConfigRoot(name = "opendc-runner") +public class OpenDCRunnerConfig { + /** + * A flag to include the OpenDC web runner extension into the build. + */ + @ConfigItem(defaultValue = "true") + boolean include; +} diff --git a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerProcessor.java b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerProcessor.java new file mode 100644 index 00000000..b9a334ac --- /dev/null +++ b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerProcessor.java @@ -0,0 +1,99 @@ +/* + * 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.runner.deployment; + +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.deployment.builditem.*; +import io.quarkus.runtime.RuntimeValue; +import org.opendc.web.runner.OpenDCRunner; +import org.opendc.web.runner.runtime.OpenDCRunnerRecorder; +import org.opendc.web.runner.runtime.OpenDCRunnerRuntimeConfig; + +import java.util.function.BooleanSupplier; + +import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT; + +/** + * Build processor for the OpenDC web runner Quarkus extension. + */ +public class OpenDCRunnerProcessor { + + private static final String FEATURE = "opendc-runner"; + + /** + * Provide the {@link FeatureBuildItem} for this Quarkus extension. + */ + @BuildStep(onlyIf = IsIncluded.class) + public FeatureBuildItem feature() { + return new FeatureBuildItem(FEATURE); + } + + /** + * Build step to index the necessary dependencies for the OpenDC runner. + */ + @BuildStep + void addDependencies(BuildProducer<IndexDependencyBuildItem> indexDependency) { + indexDependency.produce(new IndexDependencyBuildItem("org.opendc.trace", "opendc-trace-opendc")); + indexDependency.produce(new IndexDependencyBuildItem("org.opendc.trace", "opendc-trace-bitbrains")); + } + + /** + * Build step to create the runner service. + */ + @BuildStep(onlyIf = IsIncluded.class) + @Record(RUNTIME_INIT) + ServiceStartBuildItem createRunnerService(OpenDCRunnerRecorder recorder, + OpenDCRunnerRuntimeConfig config, + BuildProducer<OpenDCRunnerBuildItem> runnerBuildItem) { + RuntimeValue<OpenDCRunner> runner = recorder.createRunner(config); + runnerBuildItem.produce(new OpenDCRunnerBuildItem(runner)); + return new ServiceStartBuildItem("OpenDCRunnerService"); + } + + /** + * Build step to start the runner service. + */ + @BuildStep(onlyIf = IsIncluded.class) + @Record(RUNTIME_INIT) + void startRunnerService(ApplicationStartBuildItem start, + OpenDCRunnerBuildItem runnerBuildItem, + OpenDCRunnerRecorder recorder, + OpenDCRunnerRuntimeConfig config, + ShutdownContextBuildItem shutdownContextBuildItem) { + recorder.startRunner(runnerBuildItem.getRunner(), config,shutdownContextBuildItem); + } + + /** + * A {@link BooleanSupplier} to determine if the OpenDC web runner extension should be included. + */ + private static class IsIncluded implements BooleanSupplier { + OpenDCRunnerConfig config; + + @Override + public boolean getAsBoolean() { + return config.include; + } + } +} diff --git a/opendc-web/opendc-web-runner-quarkus/build.gradle.kts b/opendc-web/opendc-web-runner-quarkus/build.gradle.kts new file mode 100644 index 00000000..a92e03f2 --- /dev/null +++ b/opendc-web/opendc-web-runner-quarkus/build.gradle.kts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +description = "Quarkus extension for the OpenDC experiment runner" + +plugins { + `java-library-conventions` + id("io.quarkus.extension") +} + +quarkusExtension { + deploymentModule = "opendc-web-runner-quarkus-deployment" +} + +dependencies { + modules { + module("javax.annotation:javax.annotation-api") { + replacedBy("jakarta.annotation:jakarta.annotation-api", "javax has been replaced by Jakarta") + } + } + + api(projects.opendcWeb.opendcWebRunner) + + implementation(platform(libs.quarkus.bom)) + implementation(libs.quarkus.core.runtime) +} + +evaluationDependsOn(projects.opendcWeb.opendcWebRunnerQuarkusDeployment.dependencyProject.path) diff --git a/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRecorder.java b/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRecorder.java new file mode 100644 index 00000000..b243dbc3 --- /dev/null +++ b/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRecorder.java @@ -0,0 +1,84 @@ +/* + * 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.runner.runtime; + +import io.quarkus.runtime.RuntimeValue; +import io.quarkus.runtime.ShutdownContext; +import io.quarkus.runtime.annotations.Recorder; +import org.jboss.logging.Logger; +import org.opendc.web.client.runner.OpenDCRunnerClient; +import org.opendc.web.runner.OpenDCRunner; + +import java.io.File; +import java.net.URI; + +/** + * Helper class for starting the OpenDC web runner. + */ +@Recorder +public class OpenDCRunnerRecorder { + private static final Logger LOGGER = Logger.getLogger(OpenDCRunnerRecorder.class.getName()); + + /** + * Helper method to create an {@link OpenDCRunner} instance. + */ + public RuntimeValue<OpenDCRunner> createRunner(OpenDCRunnerRuntimeConfig config) { + URI apiUrl = URI.create(config.apiUrl); + OpenDCRunnerClient client = new OpenDCRunnerClient(apiUrl, null); + OpenDCRunner runner = new OpenDCRunner( + client, + new File(config.tracePath), + config.parallelism, + config.jobTimeout, + config.pollInterval, + config.heartbeatInterval + ); + + return new RuntimeValue<>(runner); + } + + /** + * Helper method to start the OpenDC runner service. + */ + public void startRunner(RuntimeValue<OpenDCRunner> runner, + OpenDCRunnerRuntimeConfig config, + ShutdownContext shutdownContext) { + if (config.enable) { + LOGGER.info("Starting OpenDC Runner in background (polling " + config.apiUrl + ")"); + + Thread thread = new Thread(() -> { + try { + // Wait for some time to allow Vert.x to bind to the local port + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + runner.getValue().run(); + }); + thread.start(); + + shutdownContext.addShutdownTask(thread::interrupt); + } + } +} diff --git a/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRuntimeConfig.java b/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRuntimeConfig.java new file mode 100644 index 00000000..e1dbf0a8 --- /dev/null +++ b/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRuntimeConfig.java @@ -0,0 +1,77 @@ +/* + * 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.runner.runtime; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +import java.time.Duration; + +/** + * Configuration for the OpenDC web runner. + */ +@ConfigRoot(phase = ConfigPhase.RUN_TIME, name = "opendc-runner") +public class OpenDCRunnerRuntimeConfig { + /** + * Flag to indicate whether the runner should be enabled. + */ + @ConfigItem(defaultValue = "true") + public boolean enable; + + /** + * The URI to the (local) API to communicate with. + */ + @ConfigItem(defaultValue = "http://${quarkus.http.host}:${quarkus.http.port}${quarkus.resteasy.path:}") + public String apiUrl; + + /** + * The path where the workload traces are located. + */ + @ConfigItem(defaultValue = "traces") + public String tracePath; + + /** + * The number of concurrent simulations + */ + @ConfigItem(defaultValue = "1") + public int parallelism; + + /** + * The maximum duration of a job. + */ + @ConfigItem(defaultValue = "10m") + public Duration jobTimeout; + + /** + * The interval between successive polls to the API. + */ + @ConfigItem(defaultValue = "30s") + public Duration pollInterval; + + /** + * The interval between successive heartbeats to the API. + */ + @ConfigItem(defaultValue = "1m") + public Duration heartbeatInterval; +} diff --git a/opendc-web/opendc-web-runner-quarkus/src/main/resources/META-INF/quarkus-extension.yaml b/opendc-web/opendc-web-runner-quarkus/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 00000000..b93b467a --- /dev/null +++ b/opendc-web/opendc-web-runner-quarkus/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,5 @@ +--- +name: "OpenDC Web Runner" +metadata: + status: "preview" + unlisted: true diff --git a/opendc-web/opendc-web-runner/Dockerfile b/opendc-web/opendc-web-runner/Dockerfile index b72f8a7f..bb606f4e 100644 --- a/opendc-web/opendc-web-runner/Dockerfile +++ b/opendc-web/opendc-web-runner/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:17-slim +FROM openjdk:18-slim MAINTAINER OpenDC Maintainers <opendc@atlarge-research.com> # Obtain (cache) Gradle wrapper diff --git a/opendc-web/opendc-web-runner/build.gradle.kts b/opendc-web/opendc-web-runner/build.gradle.kts index c1e3b976..a5723994 100644 --- a/opendc-web/opendc-web-runner/build.gradle.kts +++ b/opendc-web/opendc-web-runner/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 AtLarge Research + * Copyright (c) 2022 AtLarge Research * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,27 +24,67 @@ description = "Experiment runner for OpenDC" /* Build configuration */ plugins { - `kotlin-conventions` - `testing-conventions` - application + `kotlin-library-conventions` + distribution } -application { - mainClass.set("org.opendc.web.runner.MainKt") +val cli: SourceSet by sourceSets.creating { + compileClasspath += sourceSets["main"].output + runtimeClasspath += sourceSets["main"].output +} + +val cliImplementation: Configuration by configurations.getting { + extendsFrom(configurations["implementation"]) +} +val cliRuntimeOnly: Configuration by configurations.getting +val cliRuntimeClasspath: Configuration by configurations.getting { + extendsFrom(configurations["runtimeClasspath"]) +} + +val cliJar by tasks.creating(Jar::class) { + from(cli.output) + + archiveBaseName.set("${project.name}-cli") } dependencies { + api(projects.opendcWeb.opendcWebClient) implementation(projects.opendcCompute.opendcComputeSimulator) implementation(projects.opendcCompute.opendcComputeWorkload) implementation(projects.opendcSimulator.opendcSimulatorCore) implementation(projects.opendcTrace.opendcTraceApi) - implementation(projects.opendcWeb.opendcWebClient) implementation(libs.kotlin.logging) - implementation(libs.clikt) - implementation(libs.sentry.log4j2) - implementation(kotlin("reflect")) - runtimeOnly(projects.opendcTrace.opendcTraceOpendc) - runtimeOnly(libs.log4j.slf4j) + runtimeOnly(projects.opendcTrace.opendcTraceBitbrains) + + cliImplementation(libs.clikt) + cliImplementation(libs.sentry.log4j2) + + cliRuntimeOnly(projects.opendcTrace.opendcTraceOpendc) + cliRuntimeOnly(libs.log4j.slf4j) +} + +val createCli by tasks.creating(CreateStartScripts::class) { + dependsOn(cliJar) + + applicationName = "opendc-runner" + mainClass.set("org.opendc.web.runner.cli.MainKt") + classpath = cliJar.outputs.files + cliRuntimeClasspath + outputDir = project.buildDir.resolve("scripts") +} + +distributions { + main { + contents { + into("bin") { + from(createCli) + } + + into("lib") { + from(cliJar) + from(cliRuntimeClasspath) // Also includes main classpath + } + } + } } diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/Main.kt b/opendc-web/opendc-web-runner/src/cli/kotlin/org/opendc/web/runner/Main.kt index 7bf7e220..348a838c 100644 --- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/Main.kt +++ b/opendc-web/opendc-web-runner/src/cli/kotlin/org/opendc/web/runner/Main.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * Copyright (c) 2022 AtLarge Research * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/opendc-web/opendc-web-ui-quarkus/deployment/build.gradle.kts b/opendc-web/opendc-web-ui-quarkus-deployment/build.gradle.kts index 0f3ae8ce..5a42aaea 100644 --- a/opendc-web/opendc-web-ui-quarkus/deployment/build.gradle.kts +++ b/opendc-web/opendc-web-ui-quarkus-deployment/build.gradle.kts @@ -28,10 +28,10 @@ plugins { } dependencies { - implementation(enforcedPlatform(libs.quarkus.bom)) + implementation(platform(libs.quarkus.bom)) implementation(projects.opendcWeb.opendcWebUi) - implementation(projects.opendcWeb.opendcWebUiQuarkus.runtime) + implementation(projects.opendcWeb.opendcWebUiQuarkus) implementation(libs.quarkus.core.deployment) implementation(libs.quarkus.vertx.http.deployment) diff --git a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java index 2e4d9198..2e4d9198 100644 --- a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java +++ b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java diff --git a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java index 50c1fbe3..50c1fbe3 100644 --- a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java +++ b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java diff --git a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java index 983bb852..54782ace 100644 --- a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java +++ b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java @@ -58,7 +58,7 @@ import java.util.regex.Pattern; public class OpenDCUiProcessor { private static final String FEATURE = "opendc-ui"; - private static final GACT OPENDC_UI_WEBJAR_ARTIFACT_KEY = new GACT("org.opendc", "opendc-web-ui", null, "jar"); + private static final GACT OPENDC_UI_WEBJAR_ARTIFACT_KEY = new GACT("org.opendc.web", "opendc-web-ui", null, "jar"); private static final String OPENDC_UI_WEBJAR_STATIC_RESOURCES_PATH = "META-INF/resources/opendc-web-ui"; private static final Pattern PATH_PARAM_PATTERN = Pattern.compile("\\[(\\w+)]"); diff --git a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java index 7e0f9408..7e0f9408 100644 --- a/opendc-web/opendc-web-ui-quarkus/deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java +++ b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java diff --git a/opendc-web/opendc-web-ui-quarkus/build.gradle.kts b/opendc-web/opendc-web-ui-quarkus/build.gradle.kts index cbec021c..7f2fad20 100644 --- a/opendc-web/opendc-web-ui-quarkus/build.gradle.kts +++ b/opendc-web/opendc-web-ui-quarkus/build.gradle.kts @@ -21,3 +21,22 @@ */ description = "Quarkus extension for serving OpenDC web interface" + +plugins { + `java-library-conventions` + id("io.quarkus.extension") +} + +quarkusExtension { + deploymentModule = "opendc-web-ui-quarkus-deployment" +} + +dependencies { + implementation(platform(libs.quarkus.bom)) + + implementation(libs.quarkus.core.runtime) + implementation(libs.quarkus.vertx.http.runtime) + implementation(libs.quarkus.arc.runtime) +} + +evaluationDependsOn(projects.opendcWeb.opendcWebUiQuarkusDeployment.dependencyProject.path) diff --git a/opendc-web/opendc-web-ui-quarkus/runtime/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java b/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java index 026a9039..026a9039 100644 --- a/opendc-web/opendc-web-ui-quarkus/runtime/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java +++ b/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java diff --git a/opendc-web/opendc-web-ui-quarkus/runtime/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java b/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java index 8ae3b6a2..8ae3b6a2 100644 --- a/opendc-web/opendc-web-ui-quarkus/runtime/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java +++ b/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java diff --git a/opendc-web/opendc-web-ui-quarkus/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/opendc-web/opendc-web-ui-quarkus/src/main/resources/META-INF/quarkus-extension.yaml index 581a1779..581a1779 100644 --- a/opendc-web/opendc-web-ui-quarkus/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/opendc-web/opendc-web-ui-quarkus/src/main/resources/META-INF/quarkus-extension.yaml diff --git a/settings.gradle.kts b/settings.gradle.kts index 805e8364..88c3ffb6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -39,9 +39,11 @@ include(":opendc-web:opendc-web-proto") include(":opendc-web:opendc-web-api") include(":opendc-web:opendc-web-client") include(":opendc-web:opendc-web-ui") -include(":opendc-web:opendc-web-ui-quarkus:deployment") -include(":opendc-web:opendc-web-ui-quarkus:runtime") +include(":opendc-web:opendc-web-ui-quarkus") +include(":opendc-web:opendc-web-ui-quarkus-deployment") include(":opendc-web:opendc-web-runner") +include(":opendc-web:opendc-web-runner-quarkus") +include(":opendc-web:opendc-web-runner-quarkus-deployment") include(":opendc-simulator:opendc-simulator-core") include(":opendc-simulator:opendc-simulator-flow") include(":opendc-simulator:opendc-simulator-power") |
