diff --git a/.github/workflows/ci-code-analysis.yml b/.github/workflows/ci-code-analysis.yml index d6b8ac38a..8036fc62a 100644 --- a/.github/workflows/ci-code-analysis.yml +++ b/.github/workflows/ci-code-analysis.yml @@ -37,7 +37,7 @@ jobs: step: restore - uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' - name: Run spotbugs run: mvn -B -U compile spotbugs:check diff --git a/.github/workflows/pr-ci.yaml b/.github/workflows/pr-ci.yaml index 822d497c8..61554e0d7 100644 --- a/.github/workflows/pr-ci.yaml +++ b/.github/workflows/pr-ci.yaml @@ -110,7 +110,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' cache: 'maven' - run: git submodule init && git submodule update @@ -192,7 +192,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' cache: 'maven' - run: git submodule init && git submodule update diff --git a/.github/workflows/push-ci.yaml b/.github/workflows/push-ci.yaml index e0b832f38..0d6ae8c58 100644 --- a/.github/workflows/push-ci.yaml +++ b/.github/workflows/push-ci.yaml @@ -63,7 +63,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' cache: 'maven' - run: git submodule init && git submodule update diff --git a/README.md b/README.md index ecfaef71e..05d9d9819 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ We welcome and appreciate any contributions from our community. Please visit our Build requirements: - git -- JDK 17+ +- JDK 21+ - Maven v3+ - [Quarkus CLI](https://quarkus.io/guides/cli-tooling) v3.4.1+ (Recommended) - [Podman](https://podman.io/docs/installation) 4.7+ diff --git a/compose/auth_proxy.yml b/compose/auth_proxy.yml index 2e182cda1..a6913e17b 100644 --- a/compose/auth_proxy.yml +++ b/compose/auth_proxy.yml @@ -12,12 +12,6 @@ services: QUARKUS_HTTP_PROXY_ENABLE_FORWARDED_PREFIX: "true" QUARKUS_HTTP_ACCESS_LOG_PATTERN: long QUARKUS_HTTP_ACCESS_LOG_ENABLED: "true" - healthcheck: - test: curl --fail http://cryostat:8181/health/liveness || exit 1 - interval: 10s - retries: 3 - start_period: 30s - timeout: 5s auth: # the proxy does not actually depend on cryostat being up, but we use this # to ensure that when the smoketest tries to open the auth login page in a @@ -31,7 +25,7 @@ services: limits: cpus: "0.1" memory: 32m - image: ${OAUTH2_PROXY_IMAGE:-quay.io/oauth2-proxy/oauth2-proxy:latest} + image: ${OAUTH2_PROXY_IMAGE:-quay.io/oauth2-proxy/oauth2-proxy:latest-alpine} command: - --alpha-config=/tmp/auth_proxy_alpha_config.yml volumes: @@ -49,10 +43,10 @@ services: CRYOSTAT_PROXY_PORT: ${CRYOSTAT_PROXY_PORT} restart: unless-stopped healthcheck: - test: wget -q --spider ${CRYOSTAT_PROXY_PROTOCOL}://localhost:${CRYOSTAT_PROXY_PORT}/ping || exit 1 + test: wget --no-check-certificate -q --spider ${CRYOSTAT_PROXY_PROTOCOL}://localhost:${CRYOSTAT_PROXY_PORT}/ping || exit 1 interval: 10s retries: 3 - start_period: 30s + start_period: 10s timeout: 5s volumes: diff --git a/compose/cryostat-grafana.yml b/compose/cryostat-grafana.yml index 3c030bc38..37d376180 100644 --- a/compose/cryostat-grafana.yml +++ b/compose/cryostat-grafana.yml @@ -26,5 +26,5 @@ services: test: curl --fail http://localhost:3000/ || exit 1 retries: 3 interval: 30s - start_period: 30s + start_period: 10s timeout: 1s diff --git a/compose/cryostat.yml b/compose/cryostat.yml index 63f15ebdb..13c3bbc1f 100644 --- a/compose/cryostat.yml +++ b/compose/cryostat.yml @@ -25,8 +25,8 @@ services: CRYOSTAT_DISCOVERY_DOCKER_ENABLED: ${CRYOSTAT_DISCOVERY_DOCKER_ENABLED:-true} JAVA_OPTS_APPEND: >- -XX:+FlightRecorder - -XX:StartFlightRecording=name=onstart,settings=default,disk=true,maxage=5m - -XX:StartFlightRecording=name=startup,settings=profile,disk=true,duration=30s + -XX:StartFlightRecording=filename=/tmp,name=onstart,settings=default,disk=true,maxage=5m + -XX:StartFlightRecording=filename=/tmp,name=startup,settings=profile,disk=true,duration=30s -Dcom.sun.management.jmxremote.autodiscovery=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9091 @@ -36,12 +36,14 @@ services: -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false restart: unless-stopped - healthcheck: - test: curl --fail http://cryostat:${CRYOSTAT_HTTP_PORT}/health/liveness || exit 1 - interval: 10s - retries: 3 - start_period: 30s - timeout: 5s + # FIXME reenable this check. Somehow after upgrading to Quarkus 3.8, this check fails with 'connection refused', + # but the container comes up successfully without it and shelling into the container later to run curl succeeds + # healthcheck: + # test: curl --fail http://cryostat:${CRYOSTAT_HTTP_PORT}/health/liveness || exit 1 + # interval: 10s + # retries: 3 + # start_period: 30s + # timeout: 5s volumes: jmxtls_cfg: diff --git a/compose/cryostat_docker.yml b/compose/cryostat_docker.yml index 2060bfd63..05f925807 100644 --- a/compose/cryostat_docker.yml +++ b/compose/cryostat_docker.yml @@ -35,7 +35,7 @@ services: CRYOSTAT_DISCOVERY_JDP_ENABLED: "true" JAVA_OPTS_APPEND: >- -XX:+FlightRecorder - -XX:StartFlightRecording=name=onstart,settings=default,disk=true,maxage=5m + -XX:StartFlightRecording=filename=/tmp,name=onstart,settings=default,disk=true,maxage=5m -Dcom.sun.management.jmxremote.autodiscovery=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9091 diff --git a/compose/cryostat_k8s.yml b/compose/cryostat_k8s.yml index 9c99e84ae..aad0d546d 100644 --- a/compose/cryostat_k8s.yml +++ b/compose/cryostat_k8s.yml @@ -20,7 +20,7 @@ services: environment: CRYOSTAT_DISCOVERY_PODMAN_ENABLED: "false" CRYOSTAT_DISCOVERY_JDP_ENABLED: "true" - JAVA_OPTS_APPEND: "-XX:+FlightRecorder -XX:StartFlightRecording=name=onstart,settings=default,disk=true,maxage=5m -Dcom.sun.management.jmxremote.autodiscovery=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9091 -Dcom.sun.management.jmxremote.rmi.port=9091 -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false" + JAVA_OPTS_APPEND: "-XX:+FlightRecorder -XX:StartFlightRecording=filename=/tmp,name=onstart,settings=default,disk=true,maxage=5m -Dcom.sun.management.jmxremote.autodiscovery=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9091 -Dcom.sun.management.jmxremote.rmi.port=9091 -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false" restart: always healthcheck: test: curl --fail http://localhost:8181/health/liveness || exit 1 diff --git a/compose/db.yml b/compose/db.yml index b23fe2b73..02e015fdb 100644 --- a/compose/db.yml +++ b/compose/db.yml @@ -27,7 +27,7 @@ services: test: pg_isready -U cryostat -d cryostat || exit 1 interval: 10s retries: 3 - start_period: 30s + start_period: 10s timeout: 5s volumes: diff --git a/compose/jfr-datasource.yml b/compose/jfr-datasource.yml index 3136b1148..cc190cf08 100644 --- a/compose/jfr-datasource.yml +++ b/compose/jfr-datasource.yml @@ -29,8 +29,8 @@ services: -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false healthcheck: - test: curl --fail ${CRYOSTAT_PROXY_PROTOCOL}://localhost:${CRYOSTAT_PROXY_PORT}/ || exit 1 + test: curl --fail http://localhost:8080/ || exit 1 retries: 3 interval: 30s - start_period: 30s + start_period: 10s timeout: 1s diff --git a/compose/sample_apps/vertx-cryostat-agent.yml b/compose/sample_apps/vertx-cryostat-agent.yml index 501198a8b..cdcdf6179 100644 --- a/compose/sample_apps/vertx-cryostat-agent.yml +++ b/compose/sample_apps/vertx-cryostat-agent.yml @@ -63,7 +63,7 @@ services: - "8911" restart: always healthcheck: - test: curl --fail http://localhost:8081 || exit 1 + test: curl --fail http://localhost:8082 || exit 1 interval: 10s retries: 3 start_period: 30s @@ -102,7 +102,7 @@ services: - "8912" restart: always healthcheck: - test: curl --fail http://localhost:8081 || exit 1 + test: curl --fail http://localhost:8083 || exit 1 interval: 10s retries: 3 start_period: 30s @@ -126,7 +126,7 @@ services: - "8084:8084" restart: always healthcheck: - test: curl --fail http://localhost:8081 || exit 1 + test: curl --fail http://localhost:8084 || exit 1 interval: 10s retries: 3 start_period: 30s diff --git a/pom.xml b/pom.xml index 2c6a1a6ba..3f306488f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ ${cryostat.imageVersionLower} - 17 + 21 ${java.version} ${java.version} ${java.version} @@ -35,11 +35,8 @@ 4.0.0-SNAPSHOT 9.0.0 - 1.16.1 2.16.1 4.4 - 5.2.1 - 3.14.0 1.8.0 0.4.4 3.25.2 @@ -47,9 +44,8 @@ 1.20.1 quarkus-bom io.quarkus.platform - 3.2.12.Final - 2.2.5 - 4.1.108.Final + 3.8.6 + 2.3.10 3.6.0 3.4.1 3.7.1 @@ -60,19 +56,12 @@ 1.23.0 4.5 3.5.0 - 2 + 0 3.5.0 ${surefire.rerunFailingTestsCount} - - io.netty - netty-bom - ${io.netty.version} - pom - import - ${quarkus.platform.group-id} ${quarkus.platform.artifact-id} @@ -161,6 +150,10 @@ io.quarkus quarkus-vertx + + io.quarkus + quarkus-netty + io.quarkus quarkus-smallrye-openapi @@ -225,12 +218,10 @@ org.apache.commons commons-lang3 - ${org.apache.commons.lang3.version} commons-codec commons-codec - ${org.apache.commons.codec.version} commons-io @@ -327,7 +318,7 @@ - -Dcryostat.discovery.jdp.enabled=true -Dcryostat.discovery.podman.enabled=true -XX:+FlightRecorder -XX:StartFlightRecording=name=onstart,settings=default,disk=true,maxage=5m -Dcom.sun.management.jmxremote.autodiscovery=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9091 -Dcom.sun.management.jmxremote.rmi.port=9091 -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false + -Dcryostat.discovery.jdp.enabled=true -Dcryostat.discovery.podman.enabled=true -XX:+FlightRecorder -XX:StartFlightRecording=filename=/tmp/,name=onstart,settings=default,disk=true,maxage=5m -Dcom.sun.management.jmxremote.autodiscovery=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9091 -Dcom.sun.management.jmxremote.rmi.port=9091 -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false @@ -566,7 +557,6 @@ io.netty netty-transport-native-epoll - ${io.netty.version} ${io.netty.netty-transport-native-epoll.classifier} ${io.netty.netty-transport-native-epoll.scope} diff --git a/schema/openapi.yaml b/schema/openapi.yaml index 27a342de4..d8b24ed8c 100644 --- a/schema/openapi.yaml +++ b/schema/openapi.yaml @@ -85,6 +85,7 @@ components: DiscoveryPlugin: properties: builtin: + readOnly: true type: boolean callback: format: uri @@ -296,6 +297,7 @@ components: Target: properties: agent: + readOnly: true type: boolean alias: pattern: \S @@ -347,11 +349,6 @@ components: meta: $ref: '#/components/schemas/Meta' type: object - securitySchemes: - SecurityScheme: - description: Authentication - scheme: basic - type: http info: contact: email: cryostat-development@googlegroups.com @@ -913,7 +910,7 @@ paths: type: string requestBody: content: - application/json: + text/plain: schema: type: string responses: @@ -1906,7 +1903,7 @@ paths: responses: "200": content: - application/json: + text/plain: schema: type: string description: OK @@ -2393,13 +2390,13 @@ paths: type: integer requestBody: content: - application/json: + text/plain: schema: type: string responses: "200": content: - application/json: + text/plain: schema: type: string description: OK @@ -2429,7 +2426,7 @@ paths: responses: "200": content: - application/json: + text/plain: schema: type: string description: OK diff --git a/src/main/docker/Dockerfile.jvm b/src/main/docker/Dockerfile.jvm index 1851cd10d..7f769edb1 100644 --- a/src/main/docker/Dockerfile.jvm +++ b/src/main/docker/Dockerfile.jvm @@ -77,7 +77,7 @@ # accessed directly. (example: "foo.example.com,bar.example.com") # ### -FROM registry.access.redhat.com/ubi8/openjdk-17-runtime:1.20-3.1724181070 +FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.20-2.1725851019 ENV LANGUAGE='en_US:en' @@ -107,7 +107,7 @@ ENV SSL_TRUSTSTORE=$CONF_DIR/truststore.p12 \ USER root RUN mkdir -p $CONF_DIR \ && chmod -R g=u $CONF_DIR \ - && chown jboss:root $CONF_DIR + && chown default:root $CONF_DIR USER 185 RUN /deployments/app/truststore-setup.bash diff --git a/src/main/docker/include/truststore-setup.bash b/src/main/docker/include/truststore-setup.bash index ab4d80cfa..57f964ec1 100755 --- a/src/main/docker/include/truststore-setup.bash +++ b/src/main/docker/include/truststore-setup.bash @@ -15,7 +15,7 @@ cd "$CONF_DIR" keytool -importkeystore \ -noprompt \ -storetype PKCS12 \ - -srckeystore /usr/lib/jvm/jre-17-openjdk/lib/security/cacerts \ + -srckeystore /usr/lib/jvm/jre-openjdk/lib/security/cacerts \ -srcstorepass changeit \ -destkeystore "$SSL_TRUSTSTORE" \ -deststorepass "$SSL_TRUSTSTORE_PASS" diff --git a/src/main/java/io/cryostat/HibernateFormatMapperCustomization.java b/src/main/java/io/cryostat/HibernateFormatMapperCustomization.java new file mode 100644 index 000000000..dd390869d --- /dev/null +++ b/src/main/java/io/cryostat/HibernateFormatMapperCustomization.java @@ -0,0 +1,46 @@ +/* + * Copyright The Cryostat Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.cryostat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.quarkus.hibernate.orm.JsonFormat; +import io.quarkus.hibernate.orm.PersistenceUnitExtension; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.format.FormatMapper; +import org.hibernate.type.format.jackson.JacksonJsonFormatMapper; + +@JsonFormat +@PersistenceUnitExtension +/** + * @see https://github.com/quarkusio/quarkus/issues/42596 + */ +public class HibernateFormatMapperCustomization implements FormatMapper { + + private final JacksonJsonFormatMapper delegate = + new JacksonJsonFormatMapper(new ObjectMapper().findAndRegisterModules()); + + @Override + public T fromString( + CharSequence charSequence, JavaType javaType, WrapperOptions wrapperOptions) { + return delegate.fromString(charSequence, javaType, wrapperOptions); + } + + @Override + public String toString(T value, JavaType javaType, WrapperOptions wrapperOptions) { + return delegate.toString(value, javaType, wrapperOptions); + } +} diff --git a/src/main/java/io/cryostat/credentials/Credentials.java b/src/main/java/io/cryostat/credentials/Credentials.java index 7f840be92..4d81ab6d4 100644 --- a/src/main/java/io/cryostat/credentials/Credentials.java +++ b/src/main/java/io/cryostat/credentials/Credentials.java @@ -25,7 +25,6 @@ import io.cryostat.expressions.MatchExpression; import io.cryostat.expressions.MatchExpression.TargetMatcher; -import io.smallrye.common.annotation.Blocking; import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.transaction.Transactional; @@ -113,7 +112,6 @@ static Map notificationResult(Credential credential) throws Scri return result; } - @Blocking static Map safeResult(Credential credential, TargetMatcher matcher) throws ScriptException { Map result = new HashMap<>(); @@ -124,7 +122,6 @@ static Map safeResult(Credential credential, TargetMatcher match return result; } - @Blocking static Map safeMatchedResult(Credential credential, TargetMatcher matcher) throws ScriptException { Map result = new HashMap<>(); diff --git a/src/main/java/io/cryostat/credentials/CredentialsFinder.java b/src/main/java/io/cryostat/credentials/CredentialsFinder.java index a8f1bda00..52239c820 100644 --- a/src/main/java/io/cryostat/credentials/CredentialsFinder.java +++ b/src/main/java/io/cryostat/credentials/CredentialsFinder.java @@ -24,7 +24,6 @@ import io.cryostat.targets.Target.TargetDiscovery; import io.quarkus.vertx.ConsumeEvent; -import io.smallrye.common.annotation.Blocking; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.apache.commons.collections4.BidiMap; @@ -52,7 +51,6 @@ void onMessage(TargetDiscovery event) { } } - @Blocking public Optional getCredentialsForTarget(Target target) { return Optional.ofNullable( cache.computeIfAbsent( @@ -73,7 +71,6 @@ public Optional getCredentialsForTarget(Target target) { .orElse(null))); } - @Blocking public Optional getCredentialsForConnectUrl(URI connectUrl) { return Target.find("connectUrl", connectUrl) .singleResultOptional() diff --git a/src/main/java/io/cryostat/discovery/ContainerDiscovery.java b/src/main/java/io/cryostat/discovery/ContainerDiscovery.java index 0fdc154bf..fb9b5e2b7 100644 --- a/src/main/java/io/cryostat/discovery/ContainerDiscovery.java +++ b/src/main/java/io/cryostat/discovery/ContainerDiscovery.java @@ -187,7 +187,6 @@ public abstract class ContainerDiscovery { protected long timerId; - @Transactional void onStart(@Observes StartupEvent evt) { if (!enabled()) { return; @@ -201,7 +200,6 @@ void onStart(@Observes StartupEvent evt) { } logger.debugv("Starting {0} client", getRealm()); - queryContainers(); this.timerId = vertx.setPeriodic(pollPeriod.toMillis(), unused -> queryContainers()); } @@ -266,10 +264,9 @@ private Target toTarget(ContainerSpec desc) { target.connectUrl = connectUrl; target.alias = Optional.ofNullable(desc.Names.get(0)).orElse(desc.Id); target.labels = desc.Labels; - target.annotations = new Annotations(); - target.annotations - .cryostat() - .putAll( + target.annotations = + new Annotations( + null, Map.of( "REALM", // AnnotationKey.REALM, getRealm(), diff --git a/src/main/java/io/cryostat/discovery/CustomDiscovery.java b/src/main/java/io/cryostat/discovery/CustomDiscovery.java index 460b331a5..09d37d612 100644 --- a/src/main/java/io/cryostat/discovery/CustomDiscovery.java +++ b/src/main/java/io/cryostat/discovery/CustomDiscovery.java @@ -200,9 +200,7 @@ Response doV2Create( credential.ifPresent(c -> c.persist()); target.activeRecordings = new ArrayList<>(); - target.labels = Map.of(); - target.annotations = new Annotations(); - target.annotations.cryostat().putAll(Map.of("REALM", REALM)); + target.annotations = new Annotations(null, Map.of("REALM", REALM)); DiscoveryNode node = DiscoveryNode.target(target, BaseNodeType.JVM); target.discoveryNode = node; diff --git a/src/main/java/io/cryostat/discovery/Discovery.java b/src/main/java/io/cryostat/discovery/Discovery.java index 1eb867def..e45a28705 100644 --- a/src/main/java/io/cryostat/discovery/Discovery.java +++ b/src/main/java/io/cryostat/discovery/Discovery.java @@ -42,6 +42,7 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jwt.proc.BadJWTException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.quarkus.narayana.jta.QuarkusTransaction; import io.quarkus.runtime.ShutdownEvent; import io.quarkus.runtime.StartupEvent; import io.vertx.core.json.JsonObject; @@ -106,33 +107,42 @@ public class Discovery { @Inject Scheduler scheduler; @Inject URIUtil uriUtil; - @Transactional void onStart(@Observes StartupEvent evt) { - DiscoveryPlugin.findAll().list().stream() - .filter(p -> !p.builtin) - .forEach( - plugin -> { - var dataMap = new JobDataMap(); - dataMap.put(PLUGIN_ID_MAP_KEY, plugin.id); - dataMap.put(REFRESH_MAP_KEY, true); - JobDetail jobDetail = - JobBuilder.newJob(RefreshPluginJob.class) - .withIdentity(plugin.id.toString(), JOB_STARTUP) - .usingJobData(dataMap) - .build(); - var trigger = - TriggerBuilder.newTrigger() - .usingJobData(jobDetail.getJobDataMap()) - .startNow() - .withSchedule( - SimpleScheduleBuilder.simpleSchedule() - .withRepeatCount(0)) - .build(); - try { - scheduler.scheduleJob(jobDetail, trigger); - } catch (SchedulerException e) { - logger.warn("Failed to schedule plugin prune job", e); - } + QuarkusTransaction.requiringNew() + .run( + () -> { + DiscoveryPlugin.findAll().list().stream() + .filter(p -> !p.builtin) + .forEach( + plugin -> { + var dataMap = new JobDataMap(); + dataMap.put(PLUGIN_ID_MAP_KEY, plugin.id); + dataMap.put(REFRESH_MAP_KEY, true); + JobDetail jobDetail = + JobBuilder.newJob(RefreshPluginJob.class) + .withIdentity( + plugin.id.toString(), + JOB_STARTUP) + .usingJobData(dataMap) + .build(); + var trigger = + TriggerBuilder.newTrigger() + .usingJobData( + jobDetail.getJobDataMap()) + .startNow() + .withSchedule( + SimpleScheduleBuilder + .simpleSchedule() + .withRepeatCount(0)) + .build(); + try { + scheduler.scheduleJob(jobDetail, trigger); + } catch (SchedulerException e) { + logger.warn( + "Failed to schedule plugin prune job", + e); + } + }); }); } diff --git a/src/main/java/io/cryostat/discovery/DiscoveryNode.java b/src/main/java/io/cryostat/discovery/DiscoveryNode.java index 164292e25..3446ad51b 100644 --- a/src/main/java/io/cryostat/discovery/DiscoveryNode.java +++ b/src/main/java/io/cryostat/discovery/DiscoveryNode.java @@ -196,7 +196,14 @@ static class Listener { @Inject EventBus bus; @PrePersist - void prePersist(DiscoveryNode node) {} + void prePersist(DiscoveryNode node) { + if (node.children == null) { + node.children = new ArrayList<>(); + } + if (node.labels == null) { + node.labels = new HashMap<>(); + } + } @PostPersist void postPersist(DiscoveryNode node) {} diff --git a/src/main/java/io/cryostat/discovery/JDPDiscovery.java b/src/main/java/io/cryostat/discovery/JDPDiscovery.java index 2bc0a77d5..c448734ac 100644 --- a/src/main/java/io/cryostat/discovery/JDPDiscovery.java +++ b/src/main/java/io/cryostat/discovery/JDPDiscovery.java @@ -65,7 +65,6 @@ static JvmDiscoveryClient produceJvmDiscoveryClient() { @ConfigProperty(name = "cryostat.discovery.jdp.enabled") boolean enabled; - @Transactional void onStart(@Observes StartupEvent evt) { if (!enabled) { return; @@ -118,11 +117,9 @@ void handleJdpEvent(JvmDiscoveryEvent evt) { target.activeRecordings = new ArrayList<>(); target.connectUrl = connectUrl; target.alias = evt.getJvmDescriptor().getMainClass(); - target.labels = Map.of(); - target.annotations = new Annotations(); - target.annotations - .cryostat() - .putAll( + target.annotations = + new Annotations( + null, Map.of( "REALM", // AnnotationKey.REALM, REALM, diff --git a/src/main/java/io/cryostat/discovery/KubeApiDiscovery.java b/src/main/java/io/cryostat/discovery/KubeApiDiscovery.java index bed1a0cef..e9ccd2abe 100644 --- a/src/main/java/io/cryostat/discovery/KubeApiDiscovery.java +++ b/src/main/java/io/cryostat/discovery/KubeApiDiscovery.java @@ -129,7 +129,6 @@ protected HashMap> initialize() // Priority is set higher than default 0 such that onStart is called first before onAfterStart // This ensures realm node is persisted before initializing informers - @Transactional void onStart(@Observes @Priority(1) StartupEvent evt) { if (!enabled()) { return; @@ -143,7 +142,6 @@ void onStart(@Observes @Priority(1) StartupEvent evt) { logger.debugv("Starting {0} client", REALM); } - @Transactional void onAfterStart(@Observes StartupEvent evt) { if (!enabled() || !available()) { return; @@ -468,12 +466,13 @@ private Pair queryForNode( newNode.nodeType = nodeType.getKind(); newNode.children = new ArrayList<>(); newNode.target = null; - newNode.labels = + Map labels = kubeObj != null ? kubeObj.getMetadata().getLabels() : new HashMap<>(); // Add namespace to label to retrieve node later - newNode.labels.put(DISCOVERY_NAMESPACE_LABEL_KEY, namespace); + labels.put(DISCOVERY_NAMESPACE_LABEL_KEY, namespace); + newNode.labels = labels; return newNode; }); return Pair.of(kubeObj, node); @@ -614,14 +613,10 @@ public Target toTarget() { target.activeRecordings = new ArrayList<>(); target.connectUrl = connectUrl; target.alias = objRef.getName(); - target.labels = obj != null ? obj.getMetadata().getLabels() : new HashMap<>(); - target.annotations = new Annotations(); - target.annotations - .platform() - .putAll(obj != null ? obj.getMetadata().getAnnotations() : Map.of()); - target.annotations - .cryostat() - .putAll( + target.labels = (obj != null ? obj.getMetadata().getLabels() : new HashMap<>()); + target.annotations = + new Annotations( + obj != null ? obj.getMetadata().getAnnotations() : Map.of(), Map.of( "REALM", REALM, diff --git a/src/main/java/io/cryostat/expressions/MatchExpressionEvaluator.java b/src/main/java/io/cryostat/expressions/MatchExpressionEvaluator.java index c1acb8ae9..3053baee8 100644 --- a/src/main/java/io/cryostat/expressions/MatchExpressionEvaluator.java +++ b/src/main/java/io/cryostat/expressions/MatchExpressionEvaluator.java @@ -33,7 +33,6 @@ import io.quarkus.cache.CacheResult; import io.quarkus.cache.CompositeCacheKey; import io.quarkus.vertx.ConsumeEvent; -import io.smallrye.common.annotation.Blocking; import jakarta.annotation.Nullable; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -77,7 +76,6 @@ void onMessage(ExpressionEvent event) { } @Transactional - @Blocking @ConsumeEvent(value = Target.TARGET_JVM_DISCOVERY, blocking = true) void onMessage(TargetDiscovery event) { var target = Target.find("id", event.serviceRef().id).singleResultOptional(); diff --git a/src/main/java/io/cryostat/graphql/ActiveRecordings.java b/src/main/java/io/cryostat/graphql/ActiveRecordings.java index 0bb85bd7e..4bd7a0bf6 100644 --- a/src/main/java/io/cryostat/graphql/ActiveRecordings.java +++ b/src/main/java/io/cryostat/graphql/ActiveRecordings.java @@ -42,7 +42,6 @@ import io.cryostat.targets.Target; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.smallrye.common.annotation.Blocking; import io.smallrye.graphql.api.Nullable; import jakarta.inject.Inject; import jakarta.transaction.Transactional; @@ -64,7 +63,6 @@ public class ActiveRecordings { @ConfigProperty(name = ConfigProperties.CONNECTIONS_FAILED_TIMEOUT) Duration timeout; - @Blocking @Transactional @Mutation @Description( @@ -106,7 +104,6 @@ public List createRecording( return recordings; } - @Blocking @Transactional @Mutation @Description( @@ -138,7 +135,6 @@ public List archiveRecording( return archives; } - @Blocking @Transactional @Mutation @Description( @@ -169,7 +165,6 @@ public List stopRecording( return list; } - @Blocking @Transactional @Mutation @Description( @@ -199,7 +194,6 @@ public List deleteRecording( return list; } - @Blocking @Transactional @Mutation @Description( @@ -222,7 +216,6 @@ public List createSnapshot(@NonNull DiscoveryNodeFilter nodes) return snapshots; } - @Blocking @Transactional @Description("Start a new Flight Recording on the specified Target") public ActiveRecording doStartRecording( @@ -245,7 +238,6 @@ public ActiveRecording doStartRecording( .atMost(timeout); } - @Blocking @Transactional @Description("Create a new Flight Recorder Snapshot on the specified Target") public ActiveRecording doSnapshot(@Source Target target) { @@ -253,7 +245,6 @@ public ActiveRecording doSnapshot(@Source Target target) { return recordingHelper.createSnapshot(fTarget).await().atMost(timeout); } - @Blocking @Transactional @Description("Stop the specified Flight Recording") public ActiveRecording doStop(@Source ActiveRecording recording) throws Exception { @@ -261,7 +252,6 @@ public ActiveRecording doStop(@Source ActiveRecording recording) throws Exceptio return recordingHelper.stopRecording(ar).await().atMost(timeout); } - @Blocking @Transactional @Description("Delete the specified Flight Recording") public ActiveRecording doDelete(@Source ActiveRecording recording) { @@ -269,7 +259,6 @@ public ActiveRecording doDelete(@Source ActiveRecording recording) { return recordingHelper.deleteRecording(ar).await().atMost(timeout); } - @Blocking @Description("Archive the specified Flight Recording") public ArchivedRecording doArchive(@Source ActiveRecording recording) throws Exception { var ar = ActiveRecording.find("id", recording.id).singleResult(); @@ -317,7 +306,6 @@ public RecordingOptions asOptions() { } } - @Blocking @Transactional @Description("Updates the metadata labels for an existing Flight Recording.") public ActiveRecording doPutMetadata( diff --git a/src/main/java/io/cryostat/graphql/ArchivedRecordings.java b/src/main/java/io/cryostat/graphql/ArchivedRecordings.java index 171b355de..941dcfc64 100644 --- a/src/main/java/io/cryostat/graphql/ArchivedRecordings.java +++ b/src/main/java/io/cryostat/graphql/ArchivedRecordings.java @@ -29,7 +29,6 @@ import io.cryostat.recordings.Recordings.Metadata; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.smallrye.common.annotation.Blocking; import io.smallrye.graphql.api.Nullable; import jakarta.inject.Inject; import org.eclipse.microprofile.graphql.GraphQLApi; @@ -42,7 +41,6 @@ public class ArchivedRecordings { @Inject RecordingHelper recordingHelper; - @Blocking @Query("archivedRecordings") public TargetNodes.ArchivedRecordings listArchivedRecordings(ArchivedRecordingsFilter filter) { var r = new TargetNodes.ArchivedRecordings(); @@ -78,7 +76,6 @@ public ArchivedRecording doDelete(@Source ArchivedRecording recording) { return recording; } - @Blocking @NonNull public ArchivedRecording doPutMetadata( @Source ArchivedRecording recording, MetadataLabels metadataInput) { diff --git a/src/main/java/io/cryostat/graphql/EnvironmentNodes.java b/src/main/java/io/cryostat/graphql/EnvironmentNodes.java index c5615312a..d70859989 100644 --- a/src/main/java/io/cryostat/graphql/EnvironmentNodes.java +++ b/src/main/java/io/cryostat/graphql/EnvironmentNodes.java @@ -20,7 +20,6 @@ import io.cryostat.discovery.DiscoveryNode; import io.cryostat.graphql.RootNode.DiscoveryNodeFilter; -import io.smallrye.common.annotation.Blocking; import io.smallrye.graphql.api.Nullable; import org.eclipse.microprofile.graphql.Description; import org.eclipse.microprofile.graphql.GraphQLApi; @@ -29,7 +28,6 @@ @GraphQLApi public class EnvironmentNodes { - @Blocking @Query("environmentNodes") @Description("Get all environment nodes in the discovery tree with optional filtering") public List environmentNodes(@Nullable DiscoveryNodeFilter filter) { diff --git a/src/main/java/io/cryostat/graphql/RootNode.java b/src/main/java/io/cryostat/graphql/RootNode.java index 4af6eefa8..670bbb99f 100644 --- a/src/main/java/io/cryostat/graphql/RootNode.java +++ b/src/main/java/io/cryostat/graphql/RootNode.java @@ -24,7 +24,6 @@ import io.cryostat.graphql.matchers.LabelSelectorMatcher; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.smallrye.common.annotation.Blocking; import io.smallrye.graphql.api.Nullable; import org.eclipse.microprofile.graphql.Description; import org.eclipse.microprofile.graphql.GraphQLApi; @@ -34,14 +33,12 @@ @GraphQLApi public class RootNode { - @Blocking @Query("rootNode") @Description("Get the root target discovery node") public DiscoveryNode getRootNode() { return DiscoveryNode.getUniverse(); } - @Blocking @Description( "Get target nodes that are descendants of this node. That is, get the set of leaf nodes" + " from anywhere below this node's subtree.") diff --git a/src/main/java/io/cryostat/graphql/TargetNodes.java b/src/main/java/io/cryostat/graphql/TargetNodes.java index f2f0e3dbc..afe9eb9f8 100644 --- a/src/main/java/io/cryostat/graphql/TargetNodes.java +++ b/src/main/java/io/cryostat/graphql/TargetNodes.java @@ -33,7 +33,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import graphql.schema.DataFetchingEnvironment; -import io.smallrye.common.annotation.Blocking; import io.smallrye.graphql.api.Context; import io.smallrye.graphql.api.Nullable; import jakarta.inject.Inject; @@ -51,7 +50,6 @@ public class TargetNodes { @Inject RecordingHelper recordingHelper; @Inject TargetConnectionManager connectionManager; - @Blocking @Query("targetNodes") @Description("Get the Target discovery nodes, i.e. the leaf nodes of the discovery tree") public List getTargetNodes(DiscoveryNodeFilter filter) { @@ -69,12 +67,6 @@ public List getTargetNodes(DiscoveryNodeFilter filter) { .toList(); } - // private static Predicate distinctWith(Function fn) { - // Set observed = ConcurrentHashMap.newKeySet(); - // return t -> observed.add(fn.apply(t)); - // } - - @Blocking @Transactional public ActiveRecordings activeRecordings( @Source Target target, @Nullable ActiveRecordingsFilter filter) { @@ -90,7 +82,6 @@ public ActiveRecordings activeRecordings( return recordings; } - @Blocking public ArchivedRecordings archivedRecordings( @Source Target target, @Nullable ArchivedRecordingsFilter filter) { var fTarget = Target.getTargetById(target.id); @@ -105,7 +96,6 @@ public ArchivedRecordings archivedRecordings( return recordings; } - @Blocking @Transactional @Description("Get the active and archived recordings belonging to this target") public Recordings recordings(@Source Target target, Context context) { @@ -133,7 +123,6 @@ public Recordings recordings(@Source Target target, Context context) { return recordings; } - @Blocking @Description("Get live MBean metrics snapshot from the specified Target") public MBeanMetrics mbeanMetrics(@Source Target target) { var fTarget = Target.getTargetById(target.id); diff --git a/src/main/java/io/cryostat/recordings/RecordingOptionsBuilderFactory.java b/src/main/java/io/cryostat/recordings/RecordingOptionsBuilderFactory.java index 9b0dde250..ad77024e9 100644 --- a/src/main/java/io/cryostat/recordings/RecordingOptionsBuilderFactory.java +++ b/src/main/java/io/cryostat/recordings/RecordingOptionsBuilderFactory.java @@ -21,7 +21,6 @@ import io.cryostat.targets.Target; import io.cryostat.targets.TargetConnectionManager; -import io.smallrye.common.annotation.Blocking; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -31,7 +30,6 @@ public class RecordingOptionsBuilderFactory { @Inject RecordingOptionsCustomizerFactory customizerFactory; @Inject TargetConnectionManager connectionManager; - @Blocking public RecordingOptionsBuilder create(Target target) throws QuantityConversionException { return connectionManager.executeConnectedTask( target, diff --git a/src/main/java/io/cryostat/rules/RuleService.java b/src/main/java/io/cryostat/rules/RuleService.java index 5859766ca..164c53cdb 100644 --- a/src/main/java/io/cryostat/rules/RuleService.java +++ b/src/main/java/io/cryostat/rules/RuleService.java @@ -42,7 +42,6 @@ import io.quarkus.narayana.jta.QuarkusTransaction; import io.quarkus.runtime.StartupEvent; import io.quarkus.vertx.ConsumeEvent; -import io.smallrye.common.annotation.Blocking; import io.smallrye.mutiny.infrastructure.Infrastructure; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; @@ -77,11 +76,14 @@ public class RuleService { private final List jobs = new CopyOnWriteArrayList<>(); - @Transactional - @Blocking void onStart(@Observes StartupEvent ev) { logger.trace("RuleService started"); - Rule.streamAll().filter(r -> r.enabled).forEach(this::applyRuleToMatchingTargets); + QuarkusTransaction.joiningExisting() + .run( + () -> + Rule.streamAll() + .filter(r -> r.enabled) + .forEach(this::applyRuleToMatchingTargets)); } @ConsumeEvent(value = Target.TARGET_JVM_DISCOVERY, blocking = true) diff --git a/src/main/java/io/cryostat/targets/AgentConnection.java b/src/main/java/io/cryostat/targets/AgentConnection.java index 658b93a5f..522c6ed82 100644 --- a/src/main/java/io/cryostat/targets/AgentConnection.java +++ b/src/main/java/io/cryostat/targets/AgentConnection.java @@ -38,7 +38,6 @@ import io.cryostat.libcryostat.net.MBeanMetrics; import io.cryostat.libcryostat.sys.Clock; -import io.smallrye.common.annotation.Blocking; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.jboss.logging.Logger; @@ -57,7 +56,6 @@ class AgentConnection implements JFRConnection { @Override public void close() throws Exception {} - @Blocking @Override public void connect() throws ConnectionException { if (!client.ping().await().atMost(client.getTimeout())) { @@ -129,7 +127,6 @@ public boolean isConnected() { return true; } - @Blocking @Override public MBeanMetrics getMBeanMetrics() throws ConnectionException, diff --git a/src/main/java/io/cryostat/targets/AgentJFRService.java b/src/main/java/io/cryostat/targets/AgentJFRService.java index c96cf8330..c120df6cd 100644 --- a/src/main/java/io/cryostat/targets/AgentJFRService.java +++ b/src/main/java/io/cryostat/targets/AgentJFRService.java @@ -51,7 +51,6 @@ import io.cryostat.libcryostat.templates.Template; import io.cryostat.libcryostat.templates.TemplateType; -import io.smallrye.common.annotation.Blocking; import io.smallrye.mutiny.Uni; import io.vertx.mutiny.core.buffer.Buffer; import org.jboss.logging.Logger; @@ -82,7 +81,6 @@ public String getVersion() { return "agent"; // TODO } - @Blocking @Override public void close(IRecordingDescriptor descriptor) throws FlightRecorderException { client.deleteRecording(descriptor.getId()).await().atMost(client.getTimeout()); @@ -93,7 +91,6 @@ public void enable() throws FlightRecorderException { throw new UnimplementedException(); } - @Blocking @Override public Collection getAvailableEventTypes() throws FlightRecorderException { @@ -106,13 +103,11 @@ public Map> getAvailableRecordingOptions() return KnownRecordingOptions.DESCRIPTORS_BY_KEY_V2; } - @Blocking @Override public List getAvailableRecordings() throws FlightRecorderException { return client.activeRecordings().await().atMost(client.getTimeout()); } - @Blocking @Override public IConstrainedMap getCurrentEventTypeSettings() throws FlightRecorderException { @@ -138,13 +133,11 @@ public IConstrainedMap getRecordingOptions(IRecordingDescriptor descript return new DefaultValueMap<>(Map.of()); } - @Blocking @Override public List getServerTemplates() throws FlightRecorderException { return client.eventTemplates().await().atMost(client.getTimeout()); } - @Blocking @Override public IRecordingDescriptor getSnapshotRecording() throws FlightRecorderException { return client.startSnapshot().await().atMost(client.getTimeout()); @@ -161,7 +154,6 @@ public boolean isEnabled() { return true; } - @Blocking @Override public InputStream openStream(IRecordingDescriptor descriptor, boolean removeOnClose) throws FlightRecorderException { @@ -194,7 +186,6 @@ public IRecordingDescriptor start( throw new UnimplementedException(); } - @Blocking @Override public void stop(IRecordingDescriptor descriptor) throws FlightRecorderException { client.stopRecording(descriptor.getId()).await().atMost(client.getTimeout()); @@ -207,7 +198,6 @@ public void updateEventOptions( throw new UnimplementedException(); } - @Blocking @Override public void updateRecordingOptions( IRecordingDescriptor descriptor, IConstrainedMap newSettings) @@ -217,7 +207,6 @@ public void updateRecordingOptions( .atMost(client.getTimeout()); } - @Blocking @Override public IRecordingDescriptor start(IConstrainedMap recordingOptions, String template) throws FlightRecorderException, @@ -256,7 +245,6 @@ public IRecordingDescriptor start(IConstrainedMap recordingOptions, Stri return client.startRecording(req).await().atMost(client.getTimeout()); } - @Blocking @Override public IRecordingDescriptor start(IConstrainedMap recordingOptions, Template template) throws io.cryostat.core.FlightRecorderException, diff --git a/src/main/java/io/cryostat/targets/Target.java b/src/main/java/io/cryostat/targets/Target.java index f24f9af7c..9bc733033 100644 --- a/src/main/java/io/cryostat/targets/Target.java +++ b/src/main/java/io/cryostat/targets/Target.java @@ -21,6 +21,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -46,7 +47,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.quarkus.hibernate.orm.panache.PanacheEntity; import io.quarkus.vertx.ConsumeEvent; -import io.smallrye.common.annotation.Blocking; import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -170,14 +170,13 @@ public static record Annotations(Map platform, Map(), new HashMap<>()); + this(null, null); } public Map merged() { - Map merged = new HashMap<>(); - cryostat().entrySet().forEach((e) -> merged.put(e.getKey(), e.getValue())); - merged.putAll(platform()); - return merged; + Map merged = new HashMap<>(cryostat); + merged.putAll(platform); + return Collections.unmodifiableMap(merged); } } @@ -322,7 +321,6 @@ void onMessage(TargetDiscovery event) { @ConsumeEvent(value = Credential.CREDENTIALS_STORED, blocking = true) @Transactional - @Blocking void updateCredential(Credential credential) { Target.stream("#Target.unconnected") .forEach( @@ -341,7 +339,6 @@ void updateCredential(Credential credential) { }); } - @Blocking @PrePersist void prePersist(Target target) { if (StringUtils.isBlank(target.alias)) { @@ -352,6 +349,16 @@ void prePersist(Target target) { target.alias = encodedAlias; } + if (target.labels == null) { + target.labels = new HashMap<>(); + } + if (target.annotations == null) { + target.annotations = new Annotations(); + } + if (target.activeRecordings == null) { + target.activeRecordings = new ArrayList<>(); + } + try { if (StringUtils.isBlank(target.jvmId)) { updateTargetJvmId(target, null); @@ -361,7 +368,6 @@ void prePersist(Target target) { } } - @Blocking private void updateTargetJvmId(Target t, Credential credential) { try { t.jvmId = diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 986f4fcd1..a25c41070 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,6 +1,9 @@ quarkus.http.host=localhost quarkus.smallrye-openapi.info-title=Cryostat API (development) +quarkus.swagger-ui.enable=true +quarkus.smallrye-openapi.enable=true +quarkus.smallrye-openapi.management.enabled=true quarkus.http.cors=true # quarkus.http.cors.origins=http://localhost:9000,http://0.0.0.0:9000 diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index aeddd9cf3..17cff2fd0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -62,6 +62,8 @@ quarkus.http.limits.max-body-size=1G quarkus.vertx.prefer-native-transport=true quarkus.smallrye-openapi.path=/api +quarkus.swagger-ui.enable=false +quarkus.smallrye-openapi.management.enabled=false quarkus.smallrye-openapi.info-title=Cryostat API quarkus.smallrye-openapi.info-version=${quarkus.application.version} quarkus.smallrye-openapi.info-description=Cloud-Native JDK Flight Recorder diff --git a/src/test/java/itest/GraphQLTest.java b/src/test/java/itest/GraphQLTest.java index c6e5a5e28..a4f39be8a 100644 --- a/src/test/java/itest/GraphQLTest.java +++ b/src/test/java/itest/GraphQLTest.java @@ -70,6 +70,8 @@ class GraphQLTest extends StandardSelfTest { private final ExecutorService worker = ForkJoinPool.commonPool(); + static final long DELAY = 5_000L; + static final String TEST_RECORDING_NAME = "archivedRecording"; @Test @@ -227,7 +229,7 @@ void testStartRecordingMutationOnSpecificTarget() throws Exception { } }); - Thread.sleep(5000); + Thread.sleep(DELAY); HttpResponse resp = webClient @@ -284,7 +286,7 @@ void testStartRecordingMutationOnSpecificTarget() throws Exception { @Test @Order(4) void testArchiveMutation() throws Exception { - Thread.sleep(5000); + Thread.sleep(DELAY); String recordingName = "test"; JsonObject notificationRecording = createRecording(recordingName); Assertions.assertEquals("test", notificationRecording.getString("name")); @@ -326,7 +328,7 @@ void testArchiveMutation() throws Exception { @Test @Order(5) void testActiveRecordingMetadataMutation() throws Exception { - Thread.sleep(5000); + Thread.sleep(DELAY); String recordingName = "test"; JsonObject notificationRecording = createRecording(recordingName); Assertions.assertEquals(recordingName, notificationRecording.getString("name")); @@ -394,7 +396,7 @@ void testActiveRecordingMetadataMutation() throws Exception { @Test @Order(6) void testArchivedRecordingMetadataMutation() throws Exception { - Thread.sleep(5000); + Thread.sleep(DELAY); String recordingName = "test"; // Create a Recording JsonObject notificationRecording = createRecording(recordingName); @@ -491,7 +493,7 @@ void testArchivedRecordingMetadataMutation() throws Exception { @Order(7) void testDeleteMutation() throws Exception { // this will delete all Active and Archived recordings that match the filter input. - Thread.sleep(5000); + Thread.sleep(DELAY); String recordingName = "test"; // Create a Recording JsonObject notificationRecording = createRecording(recordingName); @@ -653,7 +655,7 @@ void testQueryForSpecificTargetsByNames() throws Exception { @Test @Order(10) public void testQueryForFilteredActiveRecordingsByNames() throws Exception { - Thread.sleep(5000); + Thread.sleep(DELAY); String recordingName1 = "test"; // Create a Recording 1 name (test) JsonObject notificationRecording = createRecording(recordingName1); @@ -687,7 +689,7 @@ public void testQueryForFilteredActiveRecordingsByNames() throws Exception { } }); - Thread.sleep(5000); + Thread.sleep(DELAY); HttpResponse resp = webClient @@ -773,7 +775,7 @@ public void shouldReturnArchivedRecordingsFilteredByNames() throws Exception { Assertions.assertTrue(listResp.isEmpty()); // Create a new recording - Thread.sleep(5000); + Thread.sleep(DELAY); String recordingName = "test"; JsonObject notificationRecording = createRecording(recordingName); Assertions.assertEquals(recordingName, notificationRecording.getString("name")); @@ -2720,7 +2722,7 @@ private JsonObject createRecording(String name) throws Exception { } }); - Thread.sleep(5000); + Thread.sleep(DELAY); HttpResponse resp = webClient @@ -2760,7 +2762,7 @@ private JsonObject stopRecording() throws Exception { } }); - Thread.sleep(5000); + Thread.sleep(DELAY); HttpResponse resp = webClient @@ -2819,7 +2821,7 @@ private JsonObject restartRecording(String name, String replace) throws Exceptio } }); - Thread.sleep(5000); + Thread.sleep(DELAY); HttpResponse resp = webClient @@ -2845,7 +2847,7 @@ private JsonObject restartRecordingWithError(String name, String replace) throws + " template: \"Profiling\", templateType: \"TARGET\", replace: \"%s\"" + " }) { name state } } } }", name, replace)); - Thread.sleep(5000); + Thread.sleep(DELAY); HttpResponse resp = webClient .extensions()