From cf6c14f96bec349d1c131ffb8cdfabbc2f5dbad0 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Tue, 1 Aug 2023 14:33:45 -0400 Subject: [PATCH] feat(agent): implement Agent HTTP dynamic JFR start (#1566) * chore(svc): extract EventOptionsBuilder to -core and use new CryostatFlightRecorderService * add unimplemented overrides * test(smoketest): enable API writes on one agent-equipped sample app * chore(serial): extract recording descriptor to -core * chore(activerecordings): clean up an error handler * feat(agent): implement dynamic start of JFR over HTTP * bump -core version --- pom.xml | 2 +- smoketest.sh | 1 + ...linkedSerializableRecordingDescriptor.java | 1 + .../SerializableRecordingDescriptor.java | 114 ------------- .../java/io/cryostat/net/AgentClient.java | 159 ++++++------------ .../java/io/cryostat/net/AgentConnection.java | 36 +++- .../java/io/cryostat/net/AgentJFRService.java | 111 +++++++++++- .../java/io/cryostat/net/NetworkModule.java | 8 +- .../recordings/EventOptionsBuilder.java | 120 ------------- .../recordings/RecordingTargetHelper.java | 14 +- .../cryostat/recordings/RecordingsModule.java | 1 + .../api/v1/TargetEventsGetHandlerTest.java | 4 +- .../api/v1/TargetRecordingGetHandlerTest.java | 5 +- .../TargetRecordingOptionsGetHandlerTest.java | 4 +- ...argetRecordingOptionsPatchHandlerTest.java | 6 +- .../TargetRecordingUploadPostHandlerTest.java | 12 +- .../v1/TargetRecordingsGetHandlerTest.java | 4 +- .../v1/TargetRecordingsPostHandlerTest.java | 4 +- .../api/v2/TargetEventsGetHandlerTest.java | 4 +- .../api/v2/TargetRecordingGetHandlerTest.java | 4 +- ...getRecordingOptionsListGetHandlerTest.java | 4 +- .../RecordingArchiveHelperTest.java | 4 +- .../recordings/RecordingTargetHelperTest.java | 21 +-- .../io/cryostat/rules/RuleProcessorTest.java | 4 +- 24 files changed, 238 insertions(+), 409 deletions(-) delete mode 100644 src/main/java/io/cryostat/jmc/serialization/SerializableRecordingDescriptor.java delete mode 100644 src/main/java/io/cryostat/recordings/EventOptionsBuilder.java diff --git a/pom.xml b/pom.xml index 963a03fcb3..33a9320e62 100644 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 2.47 - 2.21.1 + 2.22.0 15.4 3.12.0 diff --git a/smoketest.sh b/smoketest.sh index 3fed4c783e..8ca2c4b5cb 100755 --- a/smoketest.sh +++ b/smoketest.sh @@ -235,6 +235,7 @@ runDemoApps() { --env CRYOSTAT_AGENT_TRUST_ALL="true" \ --env CRYOSTAT_AGENT_AUTHORIZATION="Basic $(echo user:pass | base64)" \ --env CRYOSTAT_AGENT_REGISTRATION_PREFER_JMX="true" \ + --env CRYOSTAT_AGENT_API_WRITES_ENABLED="true" \ --rm -d quay.io/andrewazores/quarkus-test:latest # copy a jboss-client.jar into /clientlib first diff --git a/src/main/java/io/cryostat/jmc/serialization/HyperlinkedSerializableRecordingDescriptor.java b/src/main/java/io/cryostat/jmc/serialization/HyperlinkedSerializableRecordingDescriptor.java index 8d276e1cb9..000952c577 100644 --- a/src/main/java/io/cryostat/jmc/serialization/HyperlinkedSerializableRecordingDescriptor.java +++ b/src/main/java/io/cryostat/jmc/serialization/HyperlinkedSerializableRecordingDescriptor.java @@ -19,6 +19,7 @@ import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor.RecordingState; +import io.cryostat.core.serialization.SerializableRecordingDescriptor; import io.cryostat.recordings.RecordingMetadataManager.Metadata; import org.apache.commons.lang3.builder.EqualsBuilder; diff --git a/src/main/java/io/cryostat/jmc/serialization/SerializableRecordingDescriptor.java b/src/main/java/io/cryostat/jmc/serialization/SerializableRecordingDescriptor.java deleted file mode 100644 index 83ab728c51..0000000000 --- a/src/main/java/io/cryostat/jmc/serialization/SerializableRecordingDescriptor.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.jmc.serialization; - -import org.openjdk.jmc.common.unit.QuantityConversionException; -import org.openjdk.jmc.common.unit.UnitLookup; -import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; -import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor.RecordingState; - -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; - -public class SerializableRecordingDescriptor { - - protected long id; - protected String name; - protected RecordingState state; - protected long startTime; - protected long duration; - protected boolean continuous; - protected boolean toDisk; - protected long maxSize; - protected long maxAge; - - public SerializableRecordingDescriptor(IRecordingDescriptor orig) - throws QuantityConversionException { - this.id = orig.getId(); - this.name = orig.getName(); - this.state = orig.getState(); - this.startTime = orig.getStartTime().longValueIn(UnitLookup.EPOCH_MS); - this.duration = orig.getDuration().longValueIn(UnitLookup.MILLISECOND); - this.continuous = orig.isContinuous(); - this.toDisk = orig.getToDisk(); - this.maxSize = orig.getMaxSize().longValueIn(UnitLookup.BYTE); - this.maxAge = orig.getMaxAge().longValueIn(UnitLookup.MILLISECOND); - } - - public SerializableRecordingDescriptor(SerializableRecordingDescriptor o) { - this.id = o.getId(); - this.name = o.getName(); - this.state = o.getState(); - this.startTime = o.getStartTime(); - this.duration = o.getDuration(); - this.continuous = o.isContinuous(); - this.toDisk = o.getToDisk(); - this.maxSize = o.getMaxSize(); - this.maxAge = o.getMaxAge(); - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public RecordingState getState() { - return state; - } - - public long getStartTime() { - return startTime; - } - - public long getDuration() { - return duration; - } - - public boolean isContinuous() { - return continuous; - } - - public boolean getToDisk() { - return toDisk; - } - - public long getMaxSize() { - return maxSize; - } - - public long getMaxAge() { - return maxAge; - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this); - } - - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } - - @Override - public boolean equals(Object o) { - return EqualsBuilder.reflectionEquals(this, o); - } -} diff --git a/src/main/java/io/cryostat/net/AgentClient.java b/src/main/java/io/cryostat/net/AgentClient.java index 84b81c6094..beed6a8b99 100644 --- a/src/main/java/io/cryostat/net/AgentClient.java +++ b/src/main/java/io/cryostat/net/AgentClient.java @@ -25,16 +25,13 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; -import javax.management.ObjectName; import javax.script.ScriptException; import org.openjdk.jmc.common.unit.IConstrainedMap; import org.openjdk.jmc.common.unit.IConstraint; import org.openjdk.jmc.common.unit.IOptionDescriptor; -import org.openjdk.jmc.common.unit.IQuantity; import org.openjdk.jmc.common.unit.QuantityConversionException; import org.openjdk.jmc.common.unit.SimpleConstrainedMap; -import org.openjdk.jmc.common.unit.UnitLookup; import org.openjdk.jmc.flightrecorder.configuration.events.EventOptionID; import org.openjdk.jmc.flightrecorder.configuration.events.IEventTypeID; import org.openjdk.jmc.flightrecorder.configuration.internal.EventTypeIDV2; @@ -45,11 +42,15 @@ import io.cryostat.core.log.Logger; import io.cryostat.core.net.Credentials; import io.cryostat.core.net.MBeanMetrics; +import io.cryostat.core.serialization.SerializableRecordingDescriptor; +import io.cryostat.net.AgentJFRService.StartRecordingRequest; import io.cryostat.util.HttpStatusCodeIdentifier; import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpMethod; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; @@ -107,19 +108,40 @@ Future mbeanMetrics() { .map(s -> gson.fromJson(s, MBeanMetrics.class)); } + Future startRecording(StartRecordingRequest req) { + Future> f = + invoke( + HttpMethod.POST, + "/recordings", + Buffer.buffer(gson.toJson(req)), + BodyCodec.string()); + return f.map( + resp -> { + int statusCode = resp.statusCode(); + if (HttpStatusCodeIdentifier.isSuccessCode(statusCode)) { + String body = resp.body(); + return gson.fromJson(body, SerializableRecordingDescriptor.class) + .toJmcForm(); + } else if (statusCode == 403) { + throw new UnsupportedOperationException(); + } else { + throw new RuntimeException("Unknown failure"); + } + }); + } + Future> activeRecordings() { - Future> f = - invoke(HttpMethod.GET, "/recordings", BodyCodec.jsonArray()); + Future> f = invoke(HttpMethod.GET, "/recordings", BodyCodec.string()); return f.map(HttpResponse::body) .map( - arr -> - arr.stream() - .map( - o -> - (IRecordingDescriptor) - new AgentRecordingDescriptor( - (JsonObject) o)) - .toList()); + s -> + (List) + gson.fromJson( + s, + new TypeToken< + List< + SerializableRecordingDescriptor>>() {}.getType())) + .map(arr -> arr.stream().map(SerializableRecordingDescriptor::toJmcForm).toList()); } Future> eventTypes() { @@ -190,6 +212,11 @@ Future> eventTemplates() { } private Future> invoke(HttpMethod mtd, String path, BodyCodec codec) { + return invoke(mtd, path, null, codec); + } + + private Future> invoke( + HttpMethod mtd, String path, Buffer payload, BodyCodec codec) { return Future.fromCompletionStage( CompletableFuture.supplyAsync( () -> { @@ -228,10 +255,17 @@ private Future> invoke(HttpMethod mtd, String path, BodyCode } try { - return req.send() - .toCompletionStage() - .toCompletableFuture() - .get(); + if (payload != null) { + return req.sendBuffer(payload) + .toCompletionStage() + .toCompletableFuture() + .get(); + } else { + return req.send() + .toCompletionStage() + .toCompletableFuture() + .get(); + } } catch (InterruptedException | ExecutionException e) { logger.error(e); throw new RuntimeException(e); @@ -274,97 +308,6 @@ AgentClient create(URI agentUri) { } } - private static class AgentRecordingDescriptor implements IRecordingDescriptor { - - final JsonObject json; - - AgentRecordingDescriptor(JsonObject json) { - this.json = json; - } - - @Override - public IQuantity getDataStartTime() { - return getStartTime(); - } - - @Override - public IQuantity getDataEndTime() { - if (isContinuous()) { - return UnitLookup.EPOCH_MS.quantity(0); - } - return getDataStartTime().add(getDuration()); - } - - @Override - public IQuantity getDuration() { - return UnitLookup.MILLISECOND.quantity(json.getLong("duration")); - } - - @Override - public Long getId() { - return json.getLong("id"); - } - - @Override - public IQuantity getMaxAge() { - return UnitLookup.MILLISECOND.quantity(json.getLong("maxAge")); - } - - @Override - public IQuantity getMaxSize() { - return UnitLookup.BYTE.quantity(json.getLong("maxSize")); - } - - @Override - public String getName() { - return json.getString("name"); - } - - @Override - public ObjectName getObjectName() { - return null; - } - - @Override - public Map getOptions() { - return json.getJsonObject("options").getMap(); - } - - @Override - public IQuantity getStartTime() { - return UnitLookup.EPOCH_MS.quantity(json.getLong("startTime")); - } - - @Override - public RecordingState getState() { - // avoid using Enum.valueOf() since that throws an exception if the name isn't part of - // the type, and it's nicer to not throw and catch exceptions - String state = json.getString("state"); - switch (state) { - case "CREATED": - return RecordingState.CREATED; - case "RUNNING": - return RecordingState.RUNNING; - case "STOPPING": - return RecordingState.STOPPING; - case "STOPPED": - return RecordingState.STOPPED; - default: - return RecordingState.RUNNING; - } - } - - @Override - public boolean getToDisk() { - return json.getBoolean("toDisk"); - } - - @Override - public boolean isContinuous() { - return json.getBoolean("isContinuous"); - } - } - private static class AgentEventTypeInfo implements IEventTypeInfo { final JsonObject json; diff --git a/src/main/java/io/cryostat/net/AgentConnection.java b/src/main/java/io/cryostat/net/AgentConnection.java index 65ce5dd072..cce516b2d6 100644 --- a/src/main/java/io/cryostat/net/AgentConnection.java +++ b/src/main/java/io/cryostat/net/AgentConnection.java @@ -28,14 +28,16 @@ import org.openjdk.jmc.rjmx.ConnectionException; import org.openjdk.jmc.rjmx.IConnectionHandle; import org.openjdk.jmc.rjmx.ServiceNotAvailableException; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.IDException; import io.cryostat.core.net.JFRConnection; import io.cryostat.core.net.MBeanMetrics; import io.cryostat.core.sys.Clock; -import io.cryostat.core.templates.RemoteTemplateService; +import io.cryostat.core.sys.Environment; +import io.cryostat.core.sys.FileSystem; +import io.cryostat.core.templates.MergedTemplateService; import io.cryostat.core.templates.TemplateService; import io.cryostat.recordings.JvmIdHelper; @@ -45,11 +47,20 @@ public class AgentConnection implements JFRConnection { private final AgentClient client; private final JvmIdHelper idHelper; + private final FileSystem fs; + private final Environment env; private final Logger logger; - AgentConnection(AgentClient client, JvmIdHelper idHelper, Logger logger) { + AgentConnection( + AgentClient client, + JvmIdHelper idHelper, + FileSystem fs, + Environment env, + Logger logger) { this.client = client; this.idHelper = idHelper; + this.fs = fs; + this.env = env; this.logger = logger; } @@ -112,14 +123,14 @@ public int getPort() { } @Override - public IFlightRecorderService getService() + public CryostatFlightRecorderService getService() throws ConnectionException, IOException, ServiceNotAvailableException { - return new AgentJFRService(client, logger); + return new AgentJFRService(client, (MergedTemplateService) getTemplateService(), logger); } @Override public TemplateService getTemplateService() { - return new RemoteTemplateService(this); + return new MergedTemplateService(this, fs, env); } @Override @@ -141,16 +152,25 @@ public MBeanMetrics getMBeanMetrics() public static class Factory { private final AgentClient.Factory clientFactory; private final JvmIdHelper idHelper; + private final FileSystem fs; + private final Environment env; private final Logger logger; - Factory(AgentClient.Factory clientFactory, JvmIdHelper idHelper, Logger logger) { + Factory( + AgentClient.Factory clientFactory, + JvmIdHelper idHelper, + FileSystem fs, + Environment env, + Logger logger) { this.clientFactory = clientFactory; this.idHelper = idHelper; + this.fs = fs; + this.env = env; this.logger = logger; } AgentConnection createConnection(URI agentUri) { - return new AgentConnection(clientFactory.create(agentUri), idHelper, logger); + return new AgentConnection(clientFactory.create(agentUri), idHelper, fs, env, logger); } } } diff --git a/src/main/java/io/cryostat/net/AgentJFRService.java b/src/main/java/io/cryostat/net/AgentJFRService.java index bc6d68a9e7..aaa791e5ab 100644 --- a/src/main/java/io/cryostat/net/AgentJFRService.java +++ b/src/main/java/io/cryostat/net/AgentJFRService.java @@ -15,7 +15,9 @@ */ package io.cryostat.net; +import java.io.IOException; import java.io.InputStream; +import java.text.ParseException; import java.util.Collection; import java.util.List; import java.util.Map; @@ -26,34 +28,51 @@ import org.openjdk.jmc.common.unit.IDescribedMap; import org.openjdk.jmc.common.unit.IOptionDescriptor; import org.openjdk.jmc.common.unit.IQuantity; +import org.openjdk.jmc.common.unit.ITypedQuantity; +import org.openjdk.jmc.common.unit.QuantityConversionException; +import org.openjdk.jmc.common.unit.UnitLookup; import org.openjdk.jmc.flightrecorder.configuration.events.EventOptionID; import org.openjdk.jmc.flightrecorder.configuration.events.IEventTypeID; import org.openjdk.jmc.flightrecorder.configuration.internal.DefaultValueMap; +import org.openjdk.jmc.flightrecorder.configuration.internal.KnownEventOptions; +import org.openjdk.jmc.flightrecorder.configuration.internal.KnownRecordingOptions; +import org.openjdk.jmc.flightrecorder.configuration.recording.RecordingOptionsBuilder; +import org.openjdk.jmc.rjmx.ConnectionException; +import org.openjdk.jmc.rjmx.ServiceNotAvailableException; import org.openjdk.jmc.rjmx.services.jfr.FlightRecorderException; import org.openjdk.jmc.rjmx.services.jfr.IEventTypeInfo; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; +import io.cryostat.core.EventOptionsBuilder.EventOptionException; +import io.cryostat.core.EventOptionsBuilder.EventTypeException; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; +import io.cryostat.core.templates.MergedTemplateService; +import io.cryostat.core.templates.Template; +import io.cryostat.core.templates.TemplateType; -class AgentJFRService implements IFlightRecorderService { +import org.jsoup.nodes.Document; + +class AgentJFRService implements CryostatFlightRecorderService { private final AgentClient client; + private final MergedTemplateService templateService; private final Logger logger; - AgentJFRService(AgentClient client, Logger logger) { + AgentJFRService(AgentClient client, MergedTemplateService templateService, Logger logger) { this.client = client; + this.templateService = templateService; this.logger = logger; } @Override public IDescribedMap getDefaultEventOptions() { - return new DefaultValueMap<>(Map.of()); + return KnownEventOptions.OPTION_DEFAULTS_V2; } @Override public IDescribedMap getDefaultRecordingOptions() { - return new DefaultValueMap<>(Map.of()); + return KnownRecordingOptions.OPTION_DEFAULTS_V2; } @Override @@ -85,8 +104,7 @@ public Collection getAvailableEventTypes() @Override public Map> getAvailableRecordingOptions() throws FlightRecorderException { - // TODO Auto-generated method stub - return Map.of(); + return KnownRecordingOptions.DESCRIPTORS_BY_KEY_V2; } @Override @@ -203,5 +221,84 @@ public void updateRecordingOptions(IRecordingDescriptor arg0, IConstrainedMap recordingOptions, + String templateName, + TemplateType preferredTemplateType) + throws io.cryostat.core.FlightRecorderException, FlightRecorderException, + ConnectionException, IOException, ServiceNotAvailableException, + QuantityConversionException, EventOptionException, EventTypeException { + StartRecordingRequest req; + String recordingName = recordingOptions.get("name").toString(); + long duration = + (Optional.ofNullable( + (ITypedQuantity) + recordingOptions.get( + RecordingOptionsBuilder.KEY_DURATION)) + .orElse(UnitLookup.MILLISECOND.quantity(0))) + .longValueIn(UnitLookup.MILLISECOND); + long maxSize = + (Optional.ofNullable( + (ITypedQuantity) + recordingOptions.get( + RecordingOptionsBuilder.KEY_MAX_SIZE)) + .orElse(UnitLookup.BYTE.quantity(0))) + .longValueIn(UnitLookup.BYTE); + long maxAge = + (Optional.ofNullable( + (ITypedQuantity) + recordingOptions.get( + RecordingOptionsBuilder.KEY_MAX_AGE)) + .orElse(UnitLookup.MILLISECOND.quantity(0))) + .longValueIn(UnitLookup.MILLISECOND); + if (preferredTemplateType.equals(TemplateType.CUSTOM)) { + req = + new StartRecordingRequest( + recordingName, + null, + templateService + .getXml(templateName, preferredTemplateType) + .orElseThrow() + .outerHtml(), + duration, + maxSize, + maxAge); + } else { + req = + new StartRecordingRequest( + recordingName, templateName, null, duration, maxSize, maxAge); + } + try { + return client.startRecording(req).toCompletionStage().toCompletableFuture().get(); + } catch (ExecutionException | InterruptedException e) { + throw new io.cryostat.core.FlightRecorderException(e); + } + } + + @Override + public IRecordingDescriptor start( + IConstrainedMap recordingOptions, Template eventTemplate) + throws io.cryostat.core.FlightRecorderException, FlightRecorderException, + ConnectionException, IOException, FlightRecorderException, + ServiceNotAvailableException, QuantityConversionException, EventOptionException, + EventTypeException { + return CryostatFlightRecorderService.super.start(recordingOptions, eventTemplate); + } + + @Override + public IRecordingDescriptor start(IConstrainedMap recordingOptions, Document template) + throws FlightRecorderException, ParseException, IOException { + throw new UnimplementedException(); + } + public static class UnimplementedException extends IllegalStateException {} + + static record StartRecordingRequest( + String name, + String localTemplateName, + String template, + long duration, + long maxSize, + long maxAge) {} } diff --git a/src/main/java/io/cryostat/net/NetworkModule.java b/src/main/java/io/cryostat/net/NetworkModule.java index d7cffcc02d..bc28df84b2 100644 --- a/src/main/java/io/cryostat/net/NetworkModule.java +++ b/src/main/java/io/cryostat/net/NetworkModule.java @@ -97,8 +97,12 @@ static Duration provideMaxTargetTTL(Environment env) { @Provides @Singleton static AgentConnection.Factory provideAgentConnectionFactory( - AgentClient.Factory clientFactory, JvmIdHelper idHelper, Logger logger) { - return new AgentConnection.Factory(clientFactory, idHelper, logger); + AgentClient.Factory clientFactory, + JvmIdHelper idHelper, + FileSystem fs, + Environment env, + Logger logger) { + return new AgentConnection.Factory(clientFactory, idHelper, fs, env, logger); } @Provides diff --git a/src/main/java/io/cryostat/recordings/EventOptionsBuilder.java b/src/main/java/io/cryostat/recordings/EventOptionsBuilder.java deleted file mode 100644 index 9266df3d48..0000000000 --- a/src/main/java/io/cryostat/recordings/EventOptionsBuilder.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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.recordings; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.openjdk.jmc.common.unit.IConstrainedMap; -import org.openjdk.jmc.common.unit.IConstraint; -import org.openjdk.jmc.common.unit.IMutableConstrainedMap; -import org.openjdk.jmc.common.unit.IOptionDescriptor; -import org.openjdk.jmc.flightrecorder.configuration.events.EventOptionID; -import org.openjdk.jmc.flightrecorder.configuration.events.IEventTypeID; -import org.openjdk.jmc.rjmx.IConnectionHandle; -import org.openjdk.jmc.rjmx.services.jfr.IEventTypeInfo; -import org.openjdk.jmc.rjmx.services.jfr.internal.FlightRecorderServiceV2; - -import io.cryostat.core.net.JFRConnection; -import io.cryostat.core.tui.ClientWriter; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -public class EventOptionsBuilder { - - private final boolean isV2; - private final IMutableConstrainedMap map; - private Map>> knownTypes; - private Map eventIds; - - // Testing only - EventOptionsBuilder(ClientWriter cw, JFRConnection connection, Supplier v2) - throws Exception { - this.isV2 = v2.get(); - this.map = connection.getService().getDefaultEventOptions().emptyWithSameConstraints(); - knownTypes = new HashMap<>(); - eventIds = new HashMap<>(); - - if (!isV2) { - cw.println("Flight Recorder V1 is not yet supported"); - } - - for (IEventTypeInfo eventTypeInfo : connection.getService().getAvailableEventTypes()) { - eventIds.put( - eventTypeInfo.getEventTypeID().getFullKey(), eventTypeInfo.getEventTypeID()); - knownTypes.putIfAbsent( - eventTypeInfo.getEventTypeID(), - new HashMap<>(eventTypeInfo.getOptionDescriptors())); - } - } - - public EventOptionsBuilder addEvent(String typeId, String option, String value) - throws Exception { - if (!eventIds.containsKey(typeId)) { - throw new EventTypeException(typeId); - } - Map> optionDescriptors = knownTypes.get(eventIds.get(typeId)); - if (!optionDescriptors.containsKey(option)) { - throw new EventOptionException(typeId, option); - } - IConstraint constraint = optionDescriptors.get(option).getConstraint(); - Object parsedValue = constraint.parseInteractive(value); - constraint.validate(capture(parsedValue)); - this.map.put(new EventOptionID(eventIds.get(typeId), option), parsedValue); - - return this; - } - - static V capture(T t) { - // TODO clean up this generics hack - return (V) t; - } - - @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Field is never mutated") - public IConstrainedMap build() { - if (!isV2) { - return null; - } - return map; - } - - public static class EventTypeException extends Exception { - EventTypeException(String eventType) { - super(String.format("Unknown event type \"%s\"", eventType)); - } - } - - static class EventOptionException extends Exception { - EventOptionException(String eventType, String option) { - super(String.format("Unknown option \"%s\" for event \"%s\"", option, eventType)); - } - } - - public static class Factory { - private final ClientWriter cw; - - public Factory(ClientWriter cw) { - this.cw = cw; - } - - public EventOptionsBuilder create(JFRConnection connection) throws Exception { - IConnectionHandle handle = connection.getHandle(); - return new EventOptionsBuilder( - cw, connection, () -> FlightRecorderServiceV2.isAvailable(handle)); - } - } -} diff --git a/src/main/java/io/cryostat/recordings/RecordingTargetHelper.java b/src/main/java/io/cryostat/recordings/RecordingTargetHelper.java index e0e9e7bdbe..897cbbae8f 100644 --- a/src/main/java/io/cryostat/recordings/RecordingTargetHelper.java +++ b/src/main/java/io/cryostat/recordings/RecordingTargetHelper.java @@ -36,6 +36,7 @@ import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor.RecordingState; +import io.cryostat.core.EventOptionsBuilder; import io.cryostat.core.log.Logger; import io.cryostat.core.net.JFRConnection; import io.cryostat.core.templates.Template; @@ -167,12 +168,7 @@ public IRecordingDescriptor startRecording( IRecordingDescriptor desc = connection .getService() - .start( - recordingOptions, - enableEvents( - connection, - templateName, - preferredTemplateType)); + .start(recordingOptions, templateName, preferredTemplateType); String targetId = connectionDescriptor.getTargetId(); Map labels = metadata.getLabels(); @@ -595,7 +591,11 @@ private void scheduleRecordingTasks( connection, name)); return linked; } - return null; + throw new IllegalStateException( + String.format( + "Could not find expected recording" + + " named \"%s\" in target %s", + recordingName, targetId)); }); promise.complete(linkedDesc); } catch (Exception e) { diff --git a/src/main/java/io/cryostat/recordings/RecordingsModule.java b/src/main/java/io/cryostat/recordings/RecordingsModule.java index 3851c06678..45aed6d95a 100644 --- a/src/main/java/io/cryostat/recordings/RecordingsModule.java +++ b/src/main/java/io/cryostat/recordings/RecordingsModule.java @@ -33,6 +33,7 @@ import io.cryostat.configuration.ConfigurationModule; import io.cryostat.configuration.CredentialsManager; import io.cryostat.configuration.Variables; +import io.cryostat.core.EventOptionsBuilder; import io.cryostat.core.RecordingOptionsCustomizer; import io.cryostat.core.log.Logger; import io.cryostat.core.sys.Clock; diff --git a/src/test/java/io/cryostat/net/web/http/api/v1/TargetEventsGetHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v1/TargetEventsGetHandlerTest.java index d6d4565142..95cb5e5b8d 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v1/TargetEventsGetHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v1/TargetEventsGetHandlerTest.java @@ -23,11 +23,11 @@ import org.openjdk.jmc.flightrecorder.configuration.events.IEventTypeID; import org.openjdk.jmc.rjmx.services.jfr.IEventTypeInfo; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import io.cryostat.MainModule; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.jmc.serialization.SerializableEventTypeInfo; import io.cryostat.net.AuthManager; @@ -107,7 +107,7 @@ void shouldRespondWithErrorIfExceptionThrown() throws Exception { @Test void shouldRespondWithEventsList() throws Exception { JFRConnection connection = Mockito.mock(JFRConnection.class); - IFlightRecorderService service = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService service = Mockito.mock(CryostatFlightRecorderService.class); IEventTypeInfo event1 = Mockito.mock(IEventTypeInfo.class); IEventTypeID eventTypeId1 = Mockito.mock(IEventTypeID.class); diff --git a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingGetHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingGetHandlerTest.java index 9d392d2070..257a633876 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingGetHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingGetHandlerTest.java @@ -28,10 +28,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; - import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.net.AuthManager; import io.cryostat.net.HttpServer; @@ -78,7 +77,7 @@ class TargetRecordingGetHandlerTest { @Mock Logger logger; @Mock JFRConnection connection; - @Mock IFlightRecorderService service; + @Mock CryostatFlightRecorderService service; @BeforeEach void setup() { diff --git a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsGetHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsGetHandlerTest.java index a17c2ae386..9931a51408 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsGetHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsGetHandlerTest.java @@ -20,11 +20,11 @@ import org.openjdk.jmc.common.unit.IConstrainedMap; import org.openjdk.jmc.flightrecorder.configuration.recording.RecordingOptionsBuilder; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import io.cryostat.MainModule; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.net.AuthManager; import io.cryostat.net.ConnectionDescriptor; @@ -151,7 +151,7 @@ public Map answer(InvocationOnMock args) throws Throwable { resp.putHeader( Mockito.any(CharSequence.class), Mockito.any(CharSequence.class))) .thenReturn(resp); - IFlightRecorderService service = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService service = Mockito.mock(CryostatFlightRecorderService.class); Mockito.when(jfrConnection.getService()).thenReturn(service); handler.handleAuthenticated(ctx); diff --git a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsPatchHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsPatchHandlerTest.java index fa18b44b18..cabe9981b4 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsPatchHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingOptionsPatchHandlerTest.java @@ -21,12 +21,12 @@ import org.openjdk.jmc.common.unit.IConstrainedMap; import org.openjdk.jmc.flightrecorder.configuration.recording.RecordingOptionsBuilder; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.RecordingOptionsCustomizer; import io.cryostat.core.RecordingOptionsCustomizer.OptionKey; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.net.AuthManager; import io.cryostat.net.ConnectionDescriptor; @@ -136,7 +136,7 @@ public Map answer(InvocationOnMock args) throws Throwable { Mockito.when(req.formAttributes()).thenReturn(requestAttrs); HttpServerResponse resp = Mockito.mock(HttpServerResponse.class); Mockito.when(ctx.response()).thenReturn(resp); - IFlightRecorderService service = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService service = Mockito.mock(CryostatFlightRecorderService.class); Mockito.when(jfrConnection.getService()).thenReturn(service); handler.handleAuthenticated(ctx); @@ -182,7 +182,7 @@ public Map answer(InvocationOnMock args) throws Throwable { Mockito.when(req.formAttributes()).thenReturn(requestAttrs); HttpServerResponse resp = Mockito.mock(HttpServerResponse.class); Mockito.when(ctx.response()).thenReturn(resp); - IFlightRecorderService service = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService service = Mockito.mock(CryostatFlightRecorderService.class); Mockito.when(jfrConnection.getService()).thenReturn(service); handler.handleAuthenticated(ctx); diff --git a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingUploadPostHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingUploadPostHandlerTest.java index 69bda34d8a..6c18b04a0a 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingUploadPostHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingUploadPostHandlerTest.java @@ -22,11 +22,11 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.core.sys.Environment; import io.cryostat.core.sys.FileSystem; @@ -164,7 +164,7 @@ void shouldThrowExceptionIfRecordingNotFound() throws Exception { ((TargetConnectionManager.ConnectedTask) arg0.getArgument(1)) .execute(conn)); - IFlightRecorderService svc = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService svc = Mockito.mock(CryostatFlightRecorderService.class); Mockito.when(conn.getService()).thenReturn(svc); Mockito.when(svc.getAvailableRecordings()).thenReturn(Collections.emptyList()); Mockito.when(env.getEnv("GRAFANA_DATASOURCE_URL")).thenReturn(DATASOURCE_URL); @@ -195,7 +195,7 @@ void shouldDoUpload() throws Exception { ((TargetConnectionManager.ConnectedTask) arg0.getArgument(1)) .execute(conn)); - IFlightRecorderService svc = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService svc = Mockito.mock(CryostatFlightRecorderService.class); IRecordingDescriptor rec = Mockito.mock(IRecordingDescriptor.class); InputStream stream = Mockito.mock(InputStream.class); Mockito.when(conn.getService()).thenReturn(svc); @@ -266,7 +266,7 @@ void shouldHandleInvalidResponseStatusCode() throws Exception { ((TargetConnectionManager.ConnectedTask) arg0.getArgument(1)) .execute(conn)); - IFlightRecorderService svc = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService svc = Mockito.mock(CryostatFlightRecorderService.class); IRecordingDescriptor rec = Mockito.mock(IRecordingDescriptor.class); InputStream stream = Mockito.mock(InputStream.class); Mockito.when(conn.getService()).thenReturn(svc); @@ -340,7 +340,7 @@ void shouldHandleNullStatusMessage() throws Exception { ((TargetConnectionManager.ConnectedTask) arg0.getArgument(1)) .execute(conn)); - IFlightRecorderService svc = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService svc = Mockito.mock(CryostatFlightRecorderService.class); IRecordingDescriptor rec = Mockito.mock(IRecordingDescriptor.class); InputStream stream = Mockito.mock(InputStream.class); Mockito.when(conn.getService()).thenReturn(svc); @@ -414,7 +414,7 @@ void shouldHandleNullResponseBody() throws Exception { ((TargetConnectionManager.ConnectedTask) arg0.getArgument(1)) .execute(conn)); - IFlightRecorderService svc = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService svc = Mockito.mock(CryostatFlightRecorderService.class); IRecordingDescriptor rec = Mockito.mock(IRecordingDescriptor.class); InputStream stream = Mockito.mock(InputStream.class); Mockito.when(conn.getService()).thenReturn(svc); diff --git a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsGetHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsGetHandlerTest.java index 36250d8101..66468f0c29 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsGetHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsGetHandlerTest.java @@ -21,12 +21,12 @@ import org.openjdk.jmc.common.unit.IQuantity; import org.openjdk.jmc.common.unit.QuantityConversionException; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import io.cryostat.MainModule; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.jmc.serialization.HyperlinkedSerializableRecordingDescriptor; import io.cryostat.net.AuthManager; @@ -120,7 +120,7 @@ void shouldRespondWithErrorIfExceptionThrown() throws Exception { @Test void shouldRespondWithRecordingsList() throws Exception { JFRConnection connection = Mockito.mock(JFRConnection.class); - IFlightRecorderService service = Mockito.mock(IFlightRecorderService.class); + CryostatFlightRecorderService service = Mockito.mock(CryostatFlightRecorderService.class); Mockito.when( connectionManager.executeConnectedTask( diff --git a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsPostHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsPostHandlerTest.java index 3b7fb2fd79..5192cdb799 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsPostHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v1/TargetRecordingsPostHandlerTest.java @@ -25,12 +25,12 @@ import org.openjdk.jmc.common.unit.IQuantity; import org.openjdk.jmc.common.unit.QuantityConversionException; import org.openjdk.jmc.flightrecorder.configuration.recording.RecordingOptionsBuilder; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import io.cryostat.MainModule; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.core.templates.TemplateService; import io.cryostat.core.templates.TemplateType; @@ -81,7 +81,7 @@ class TargetRecordingsPostHandlerTest { Gson gson = MainModule.provideGson(logger); @Mock JFRConnection connection; - @Mock IFlightRecorderService service; + @Mock CryostatFlightRecorderService service; @Mock TemplateService templateService; @Mock RoutingContext ctx; @Mock HttpServerRequest req; diff --git a/src/test/java/io/cryostat/net/web/http/api/v2/TargetEventsGetHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v2/TargetEventsGetHandlerTest.java index 621d295536..2b6b896ba0 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v2/TargetEventsGetHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v2/TargetEventsGetHandlerTest.java @@ -27,11 +27,11 @@ import org.openjdk.jmc.flightrecorder.configuration.events.IEventTypeID; import org.openjdk.jmc.rjmx.services.jfr.IEventTypeInfo; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import io.cryostat.MainModule; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.jmc.serialization.SerializableEventTypeInfo; import io.cryostat.net.AuthManager; @@ -59,7 +59,7 @@ class TargetEventsGetHandlerTest { @Mock CredentialsManager credentialsManager; @Mock TargetConnectionManager targetConnectionManager; @Mock Logger logger; - @Mock IFlightRecorderService service; + @Mock CryostatFlightRecorderService service; @Mock JFRConnection connection; Gson gson = MainModule.provideGson(logger); diff --git a/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingGetHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingGetHandlerTest.java index fefa310de5..d6aa5b6f25 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingGetHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingGetHandlerTest.java @@ -23,11 +23,11 @@ import java.util.Random; import org.openjdk.jmc.rjmx.services.jfr.FlightRecorderException; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.net.AuthManager; import io.cryostat.net.ConnectionDescriptor; @@ -139,7 +139,7 @@ class Behaviour { @Mock RoutingContext ctx; @Mock JWT token; @Mock JFRConnection conn; - @Mock IFlightRecorderService svc; + @Mock CryostatFlightRecorderService svc; @Test void shouldRespond404IfNotFound() throws Exception { diff --git a/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingOptionsListGetHandlerTest.java b/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingOptionsListGetHandlerTest.java index ed576cb2e3..e60b68b1dc 100644 --- a/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingOptionsListGetHandlerTest.java +++ b/src/test/java/io/cryostat/net/web/http/api/v2/TargetRecordingOptionsListGetHandlerTest.java @@ -23,11 +23,11 @@ import java.util.concurrent.CompletableFuture; import org.openjdk.jmc.common.unit.IOptionDescriptor; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import io.cryostat.MainModule; import io.cryostat.configuration.CredentialsManager; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.net.AuthManager; import io.cryostat.net.ConnectionDescriptor; @@ -59,7 +59,7 @@ class TargetRecordingOptionsListGetHandlerTest { @Mock AuthManager auth; @Mock CredentialsManager credentialsManager; @Mock TargetConnectionManager targetConnectionManager; - @Mock IFlightRecorderService service; + @Mock CryostatFlightRecorderService service; @Mock JFRConnection connection; @Mock Logger logger; Gson gson = MainModule.provideGson(logger); diff --git a/src/test/java/io/cryostat/recordings/RecordingArchiveHelperTest.java b/src/test/java/io/cryostat/recordings/RecordingArchiveHelperTest.java index 492106b4d0..13d786eacd 100644 --- a/src/test/java/io/cryostat/recordings/RecordingArchiveHelperTest.java +++ b/src/test/java/io/cryostat/recordings/RecordingArchiveHelperTest.java @@ -34,10 +34,10 @@ import javax.management.remote.JMXServiceURL; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.core.sys.Clock; import io.cryostat.core.sys.FileSystem; @@ -91,7 +91,7 @@ class RecordingArchiveHelperTest { @Mock Notification notification; @Mock Notification.Builder notificationBuilder; @Mock JFRConnection connection; - @Mock IFlightRecorderService service; + @Mock CryostatFlightRecorderService service; @Mock Vertx vertx; @Mock io.vertx.core.file.FileSystem vertxFs; diff --git a/src/test/java/io/cryostat/recordings/RecordingTargetHelperTest.java b/src/test/java/io/cryostat/recordings/RecordingTargetHelperTest.java index 1b330dece9..79e3a26c49 100644 --- a/src/test/java/io/cryostat/recordings/RecordingTargetHelperTest.java +++ b/src/test/java/io/cryostat/recordings/RecordingTargetHelperTest.java @@ -33,15 +33,14 @@ import org.openjdk.jmc.common.unit.IConstrainedMap; import org.openjdk.jmc.common.unit.IQuantity; import org.openjdk.jmc.common.unit.QuantityConversionException; -import org.openjdk.jmc.flightrecorder.configuration.events.EventOptionID; import org.openjdk.jmc.flightrecorder.configuration.recording.RecordingOptionsBuilder; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor.RecordingState; +import io.cryostat.core.EventOptionsBuilder; import io.cryostat.core.log.Logger; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; -import io.cryostat.core.templates.TemplateService; import io.cryostat.core.templates.TemplateType; import io.cryostat.jmc.serialization.HyperlinkedSerializableRecordingDescriptor; import io.cryostat.messaging.notifications.Notification; @@ -90,7 +89,7 @@ public class RecordingTargetHelperTest { @Mock Logger logger; @Mock JFRConnection connection; - @Mock IFlightRecorderService service; + @Mock CryostatFlightRecorderService service; @BeforeEach void setup() { @@ -710,13 +709,10 @@ public Object answer(InvocationOnMock invocation) throws Throwable { Mockito.when(service.getAvailableRecordings()) .thenReturn(Collections.emptyList(), List.of(recordingDescriptor)); - Mockito.when(service.start(Mockito.any(), Mockito.any())).thenReturn(recordingDescriptor); - - TemplateService templateService = Mockito.mock(TemplateService.class); - IConstrainedMap events = Mockito.mock(IConstrainedMap.class); - Mockito.when(connection.getTemplateService()).thenReturn(templateService); - Mockito.when(templateService.getEvents(Mockito.any(), Mockito.any())) - .thenReturn(Optional.of(events)); + Mockito.when( + service.start( + Mockito.any(), Mockito.eq(templateName), Mockito.eq(templateType))) + .thenReturn(recordingDescriptor); Mockito.when( recordingMetadataManager.setRecordingMetadata( @@ -739,7 +735,8 @@ public Future answer(InvocationOnMock invocation) metadata, false); - Mockito.verify(service).start(Mockito.any(), Mockito.any()); + Mockito.verify(service) + .start(Mockito.any(), Mockito.eq(templateName), Mockito.eq(templateType)); HyperlinkedSerializableRecordingDescriptor linkedDesc = new HyperlinkedSerializableRecordingDescriptor(recordingDescriptor, null, null); diff --git a/src/test/java/io/cryostat/rules/RuleProcessorTest.java b/src/test/java/io/cryostat/rules/RuleProcessorTest.java index bb47851bac..c8f61c302a 100644 --- a/src/test/java/io/cryostat/rules/RuleProcessorTest.java +++ b/src/test/java/io/cryostat/rules/RuleProcessorTest.java @@ -25,7 +25,6 @@ import org.openjdk.jmc.common.unit.IConstrainedMap; import org.openjdk.jmc.flightrecorder.configuration.recording.RecordingOptionsBuilder; -import org.openjdk.jmc.rjmx.services.jfr.IFlightRecorderService; import org.openjdk.jmc.rjmx.services.jfr.IRecordingDescriptor; import io.cryostat.MockVertx; @@ -33,6 +32,7 @@ import io.cryostat.configuration.CredentialsManager.CredentialsEvent; import io.cryostat.core.log.Logger; import io.cryostat.core.net.Credentials; +import io.cryostat.core.net.CryostatFlightRecorderService; import io.cryostat.core.net.JFRConnection; import io.cryostat.core.net.discovery.JvmDiscoveryClient.EventKind; import io.cryostat.core.templates.TemplateType; @@ -83,7 +83,7 @@ class RuleProcessorTest { @Mock Logger logger; @Mock JFRConnection connection; - @Mock IFlightRecorderService service; + @Mock CryostatFlightRecorderService service; @BeforeEach void setup() {