Skip to content

Commit

Permalink
chore(db): apply active record validation constraints (#257)
Browse files Browse the repository at this point in the history
* chore(db): apply active record validation constraints

* add discovery plugins to universe tree on registration
  • Loading branch information
andrewazores authored Jan 23, 2024
1 parent 29e7abe commit cfa3230
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 25 deletions.
12 changes: 10 additions & 2 deletions src/main/java/io/cryostat/credentials/Credential.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/io/cryostat/discovery/Discovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,11 @@ public Map<String, Object> register(JsonObject body) throws URISyntaxException {
DiscoveryPlugin plugin = new DiscoveryPlugin();
plugin.callback = callbackUri;
plugin.realm = DiscoveryNode.environment(realmName, DiscoveryNode.REALM);
plugin.builtin = false;
plugin.persist();

DiscoveryNode.getUniverse().children.add(plugin.realm);

return Map.of(
"meta",
Map.of(
Expand All @@ -155,7 +158,13 @@ public Map<String, Map<String, String>> publish(
plugin.realm.children.clear();
plugin.persist();
plugin.realm.children.addAll(body);
body.forEach(b -> b.persist());
body.forEach(
b -> {
if (b.target != null) {
b.target.discoveryNode = b;
}
b.persist();
});
plugin.persist();

return Map.of(
Expand All @@ -176,6 +185,7 @@ public Map<String, Map<String, String>> deregister(@RestPath UUID id, @RestQuery
throw new ForbiddenException();
}
plugin.delete();
DiscoveryNode.getUniverse().children.remove(plugin.realm);
return Map.of(
"meta",
Map.of(
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/io/cryostat/discovery/DiscoveryNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -58,26 +61,30 @@ 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<String, String> labels = new HashMap<>();

@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true)
@JsonView(Views.Nested.class)
@Nullable
public List<DiscoveryNode> children = new ArrayList<>();

@OneToOne(
mappedBy = "discoveryNode",
cascade = {CascadeType.ALL},
fetch = FetchType.LAZY,
orphanRemoval = true)
@Nullable
@JsonInclude(value = Include.NON_NULL)
@JsonView(Views.Flat.class)
public Target target;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/cryostat/discovery/DiscoveryPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -56,19 +58,22 @@ public class DiscoveryPlugin extends PanacheEntityBase {
@Column(name = "id")
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
@NotNull
public UUID id;

@OneToOne(
optional = false,
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
Expand Down
22 changes: 12 additions & 10 deletions src/main/java/io/cryostat/recordings/ActiveRecording.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand Down
16 changes: 11 additions & 5 deletions src/main/java/io/cryostat/rules/Rule.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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")
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/io/cryostat/rules/Rules.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ public RestResponse<V2Response> create(Rule rule) {
if (ruleExists) {
throw new RuleExistsException(rule.name);
}
if (rule.description == null) {
rule.description = "";
}
rule.persist();
return ResponseBuilder.create(
Response.Status.CREATED,
Expand Down
21 changes: 15 additions & 6 deletions src/main/java/io/cryostat/targets/Target.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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<String, String> 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<ActiveRecording> 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();
}
Expand Down

0 comments on commit cfa3230

Please sign in to comment.