Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(db): apply active record validation constraints #257

Merged
merged 4 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading