diff --git a/src/main/java/io/cryostat/credentials/Credential.java b/src/main/java/io/cryostat/credentials/Credential.java index af0d4f9a7..5f24dc8cd 100644 --- a/src/main/java/io/cryostat/credentials/Credential.java +++ b/src/main/java/io/cryostat/credentials/Credential.java @@ -19,6 +19,7 @@ import io.cryostat.ws.MessagingServer; import io.cryostat.ws.Notification; +import com.fasterxml.jackson.annotation.JsonProperty; import io.quarkus.hibernate.orm.panache.PanacheEntity; import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.enterprise.context.ApplicationScoped; @@ -33,6 +34,8 @@ import jakarta.persistence.PostPersist; import jakarta.persistence.PostRemove; import jakarta.persistence.PostUpdate; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import org.hibernate.annotations.ColumnTransformer; import org.projectnessie.cel.tools.ScriptException; @@ -46,18 +49,23 @@ public class Credential extends PanacheEntity { @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn(name = "matchExpression") + @NotNull public MatchExpression matchExpression; @ColumnTransformer( read = "pgp_sym_decrypt(username, current_setting('encrypt.key'))", write = "pgp_sym_encrypt(?, current_setting('encrypt.key'))") - @Column(nullable = false, updatable = false, columnDefinition = "bytea") + @Column(updatable = false, columnDefinition = "bytea") + @NotBlank + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String username; @ColumnTransformer( read = "pgp_sym_decrypt(password, current_setting('encrypt.key'))", write = "pgp_sym_encrypt(?, current_setting('encrypt.key'))") - @Column(nullable = false, updatable = false, columnDefinition = "bytea") + @Column(updatable = false, columnDefinition = "bytea") + @NotBlank + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String password; @ApplicationScoped diff --git a/src/main/java/io/cryostat/discovery/Discovery.java b/src/main/java/io/cryostat/discovery/Discovery.java index 9de683c48..8943e9ac2 100644 --- a/src/main/java/io/cryostat/discovery/Discovery.java +++ b/src/main/java/io/cryostat/discovery/Discovery.java @@ -127,6 +127,7 @@ public Map register(JsonObject body) throws URISyntaxException { DiscoveryPlugin plugin = new DiscoveryPlugin(); plugin.callback = callbackUri; plugin.realm = DiscoveryNode.environment(realmName, DiscoveryNode.REALM); + plugin.builtin = false; plugin.persist(); return Map.of( diff --git a/src/main/java/io/cryostat/discovery/DiscoveryNode.java b/src/main/java/io/cryostat/discovery/DiscoveryNode.java index 14ecfecc3..46ccf2456 100644 --- a/src/main/java/io/cryostat/discovery/DiscoveryNode.java +++ b/src/main/java/io/cryostat/discovery/DiscoveryNode.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.annotation.JsonView; import io.quarkus.hibernate.orm.panache.PanacheEntity; import io.vertx.mutiny.core.eventbus.EventBus; +import jakarta.annotation.Nullable; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.persistence.CascadeType; @@ -43,6 +44,8 @@ import jakarta.persistence.PostRemove; import jakarta.persistence.PostUpdate; import jakarta.persistence.PrePersist; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; import org.jboss.logging.Logger; @@ -58,19 +61,22 @@ public class DiscoveryNode extends PanacheEntity { @Column(unique = false, nullable = false, updatable = false) @JsonView(Views.Flat.class) + @NotBlank public String name; @Column(unique = false, nullable = false, updatable = false) @JsonView(Views.Flat.class) + @NotBlank public String nodeType; @JdbcTypeCode(SqlTypes.JSON) - @Column(nullable = false) + @NotNull @JsonView(Views.Flat.class) public Map labels = new HashMap<>(); @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true) @JsonView(Views.Nested.class) + @Nullable public List children = new ArrayList<>(); @OneToOne( @@ -78,6 +84,7 @@ public class DiscoveryNode extends PanacheEntity { cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, orphanRemoval = true) + @Nullable @JsonInclude(value = Include.NON_NULL) @JsonView(Views.Flat.class) public Target target; diff --git a/src/main/java/io/cryostat/discovery/DiscoveryPlugin.java b/src/main/java/io/cryostat/discovery/DiscoveryPlugin.java index c49f3c986..b893ebd9e 100644 --- a/src/main/java/io/cryostat/discovery/DiscoveryPlugin.java +++ b/src/main/java/io/cryostat/discovery/DiscoveryPlugin.java @@ -24,6 +24,7 @@ import io.cryostat.credentials.Credential; +import com.fasterxml.jackson.annotation.JsonProperty; import io.quarkus.hibernate.orm.panache.PanacheEntityBase; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -37,6 +38,7 @@ import jakarta.persistence.Id; import jakarta.persistence.OneToOne; import jakarta.persistence.PrePersist; +import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @@ -56,6 +58,7 @@ public class DiscoveryPlugin extends PanacheEntityBase { @Column(name = "id") @GeneratedValue(generator = "UUID") @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @NotNull public UUID id; @OneToOne( @@ -63,12 +66,14 @@ public class DiscoveryPlugin extends PanacheEntityBase { cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.LAZY) + @NotNull public DiscoveryNode realm; @Column(unique = true, updatable = false) @Convert(converter = UriConverter.class) public URI callback; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) public boolean builtin; @ApplicationScoped diff --git a/src/main/java/io/cryostat/recordings/ActiveRecording.java b/src/main/java/io/cryostat/recordings/ActiveRecording.java index 913dc6652..f1c07b185 100644 --- a/src/main/java/io/cryostat/recordings/ActiveRecording.java +++ b/src/main/java/io/cryostat/recordings/ActiveRecording.java @@ -35,7 +35,6 @@ import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; @@ -49,6 +48,9 @@ import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; import jakarta.transaction.Transactional; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PositiveOrZero; import jdk.jfr.RecordingState; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; @@ -65,22 +67,22 @@ public class ActiveRecording extends PanacheEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "target_id") + @NotNull public Target target; - @Column(nullable = false) - public String name; + @NotBlank public String name; - public long remoteId; - public RecordingState state; - public long duration; - public long startTime; + @PositiveOrZero public long remoteId; + @NotNull public RecordingState state; + @PositiveOrZero public long duration; + @PositiveOrZero public long startTime; public boolean continuous; public boolean toDisk; - public long maxSize; - public long maxAge; + @PositiveOrZero public long maxSize; + @PositiveOrZero public long maxAge; @JdbcTypeCode(SqlTypes.JSON) - @Column(nullable = false) + @NotNull public Metadata metadata; public static ActiveRecording from(Target target, LinkedRecordingDescriptor descriptor) { diff --git a/src/main/java/io/cryostat/rules/Rule.java b/src/main/java/io/cryostat/rules/Rule.java index 3ed9a4aa4..0e55c3bf9 100644 --- a/src/main/java/io/cryostat/rules/Rule.java +++ b/src/main/java/io/cryostat/rules/Rule.java @@ -21,6 +21,7 @@ import io.cryostat.ws.MessagingServer; import io.cryostat.ws.Notification; +import com.fasterxml.jackson.annotation.JsonIgnore; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.quarkus.hibernate.orm.panache.PanacheEntity; import io.vertx.mutiny.core.eventbus.EventBus; @@ -38,6 +39,7 @@ import jakarta.persistence.PostUpdate; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.PositiveOrZero; @Entity @@ -50,17 +52,19 @@ public class Rule extends PanacheEntity { public static final String RULE_ADDRESS = "io.cryostat.rules.Rule"; - @Column(unique = true, nullable = false, updatable = false) + @Column(unique = true, updatable = false) + @NotBlank public String name; - public String description; + @NotNull public String description; @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn(name = "matchExpression") + @NotNull public MatchExpression matchExpression; @Column(nullable = false) - @NotBlank(message = "eventSpecifier cannot be blank") + @NotBlank public String eventSpecifier; @PositiveOrZero(message = "archivalPeriodSeconds must be positive or zero") @@ -72,10 +76,10 @@ public class Rule extends PanacheEntity { @PositiveOrZero(message = "archivalPeriodSeconds must be positive or zero") public int preservedArchives; - @Min(message = "maxAgeSeconds must be greater than 0 or -1", value = -1) + @Min(message = "maxAgeSeconds must be greater than -1", value = -1) public int maxAgeSeconds; - @Min(message = "maxAgeSeconds must be greater than 0 or -1", value = -1) + @Min(message = "maxAgeSeconds must be greater than -1", value = -1) public int maxSizeBytes; public boolean enabled; @@ -84,11 +88,13 @@ public String getName() { return this.name; } + @JsonIgnore public String getRecordingName() { // FIXME do something other than simply prepending "auto_" return String.format("auto_%s", name); } + @JsonIgnore public boolean isArchiver() { return preservedArchives > 0 && archivalPeriodSeconds > 0; } diff --git a/src/main/java/io/cryostat/rules/Rules.java b/src/main/java/io/cryostat/rules/Rules.java index 754ce4cc7..91c2f4ca6 100644 --- a/src/main/java/io/cryostat/rules/Rules.java +++ b/src/main/java/io/cryostat/rules/Rules.java @@ -71,6 +71,9 @@ public RestResponse create(Rule rule) { if (ruleExists) { throw new RuleExistsException(rule.name); } + if (rule.description == null) { + rule.description = ""; + } rule.persist(); return ResponseBuilder.create( Response.Status.CREATED, diff --git a/src/main/java/io/cryostat/targets/Target.java b/src/main/java/io/cryostat/targets/Target.java index f96085453..1dd7b1e6b 100644 --- a/src/main/java/io/cryostat/targets/Target.java +++ b/src/main/java/io/cryostat/targets/Target.java @@ -36,6 +36,7 @@ import io.cryostat.ws.Notification; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.quarkus.hibernate.orm.panache.PanacheEntity; import io.quarkus.vertx.ConsumeEvent; @@ -54,6 +55,8 @@ import jakarta.persistence.PostUpdate; import jakarta.persistence.PrePersist; import jakarta.transaction.Transactional; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import org.apache.commons.lang3.StringUtils; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; @@ -65,40 +68,46 @@ public class Target extends PanacheEntity { public static final String TARGET_JVM_DISCOVERY = "TargetJvmDiscovery"; - @Column(unique = true, nullable = false, updatable = false) + @Column(unique = true, updatable = false) + @NotNull public URI connectUrl; - @Column(unique = true, nullable = false) + @Column(unique = true) + @NotBlank public String alias; public String jvmId; @JdbcTypeCode(SqlTypes.JSON) - @Column(nullable = false) + @NotNull public Map labels = new HashMap<>(); @JdbcTypeCode(SqlTypes.JSON) - @Column(nullable = false) + @NotNull public Annotations annotations = new Annotations(); - @JsonIgnore @OneToMany( mappedBy = "target", cascade = {CascadeType.ALL}, orphanRemoval = true) + @NotNull + @JsonIgnore public List activeRecordings = new ArrayList<>(); - @JsonIgnore @OneToOne( cascade = {CascadeType.ALL}, orphanRemoval = true) @JoinColumn(name = "discoveryNode") + @NotNull + @JsonIgnore public DiscoveryNode discoveryNode; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) public boolean isAgent() { return Set.of("http", "https", "cryostat-agent").contains(connectUrl.getScheme()); } + @JsonIgnore public String targetId() { return this.connectUrl.toString(); }