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

feat(discovery): port kubeApi discovery to v3 #325

Merged
merged 30 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4d11b8a
feat(discovery): port kubeApi discovery to v3
tthvo Jan 26, 2024
f28fe85
chore(discovery): clean up unused codes and address reviews
tthvo Feb 8, 2024
0661f47
build(deps): remove unused mvn deps
tthvo Mar 22, 2024
ca24b07
feat(discovery): implement discovery logic for FOUND events
tthvo Mar 22, 2024
d29a798
feat(discovery): clean up and implement LOST events
tthvo Mar 27, 2024
f262aa8
chore(typo): fix typo
tthvo Mar 27, 2024
b7a68a7
chore(license): add missing license headers
tthvo Mar 27, 2024
aba6f8a
fix(orm): fix unwrap exception when using enum
tthvo Mar 27, 2024
0f63fa3
chore(logs): fix broken logs format
tthvo Mar 27, 2024
e678a3c
fix(discovery): ignore when target does not exist in db
tthvo Mar 27, 2024
06ee05b
fix(discovery): fix DELETE event handler
tthvo Apr 2, 2024
0adbc41
chore(spotless): add missing spotless fix
tthvo Apr 2, 2024
010909e
chore(k8s): correct labels
tthvo Apr 4, 2024
8ff1804
fixup(k8s): add missing changes for watch namespaces from Andrew
tthvo Apr 9, 2024
2fc59af
fix(k8s): fix string comparison
tthvo Apr 9, 2024
e3fc083
fix(k8s): fix duplicate namespace nodes
tthvo Apr 9, 2024
8746ff5
fix(k8s): fix realm node not found and deletion constraint violation
tthvo Apr 9, 2024
24bf1b5
fix(k8s): rebuild tree on endpoint events
tthvo Apr 22, 2024
4bddb2a
feat(discovery): define parent reference for discovery node
tthvo Apr 22, 2024
a1ea98a
feat(discovery): cache discovery queries
tthvo Apr 22, 2024
3029fe3
fix(discovery): fix bugs causing infinite loop in worker thread
tthvo Apr 22, 2024
4252166
fix(discovery): ensure cascade remove when removing nodes
tthvo Apr 22, 2024
2d4a4cf
fix(discovery): ensure all nodes have parent ref
tthvo Apr 22, 2024
543e103
fix(discovery): properly delete nodes when targets disappear
tthvo Apr 22, 2024
4221626
fix(discovery): only fetch target in namespace of interest
tthvo Apr 22, 2024
559a53d
chore(discovery): clean up and address reviews
tthvo Apr 24, 2024
fea4391
fixup(discovery): use optional for injected list
tthvo Apr 24, 2024
5f1d89e
fixup(transaction): run handler in correct transaction context
tthvo Apr 24, 2024
eddd41e
test(integration): fix broken integration tests
tthvo Apr 24, 2024
978cc5a
fix(spotbugs): remove unused equals override
tthvo Apr 24, 2024
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
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<surefire-plugin.version>3.2.5</surefire-plugin.version>
<surefire.rerunFailingTestsCount>2</surefire.rerunFailingTestsCount>
<failsafe-plugin.version>3.2.5</failsafe-plugin.version>
<io.fabric8.client.version>6.7.2</io.fabric8.client.version>
<failsafe.rerunFailingTestsCount>${surefire.rerunFailingTestsCount}</failsafe.rerunFailingTestsCount>
</properties>
<dependencyManagement>
Expand Down Expand Up @@ -217,6 +218,11 @@
<version>${com.google.java-format.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>${io.fabric8.client.version}</version>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
Expand Down Expand Up @@ -249,7 +255,6 @@
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

</dependencies>
<build>
<plugins>
Expand Down
47 changes: 40 additions & 7 deletions src/main/java/io/cryostat/discovery/ContainerDiscovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,19 +164,21 @@ void onStart(@Observes StartupEvent evt) {
getClass().getName(), socketPath);
return;
}
logger.infov("{0} started", getClass().getName());

DiscoveryNode universe = DiscoveryNode.getUniverse();
if (DiscoveryNode.getRealm(getRealm()).isEmpty()) {
DiscoveryPlugin plugin = new DiscoveryPlugin();
DiscoveryNode node = DiscoveryNode.environment(getRealm(), DiscoveryNode.REALM);
DiscoveryNode node = DiscoveryNode.environment(getRealm(), BaseNodeType.REALM);
plugin.realm = node;
plugin.builtin = true;
universe.children.add(node);
node.parent = universe;
plugin.persist();
universe.persist();
}

logger.infov("Starting {0} client", getRealm());

queryContainers();
this.timerId = vertx.setPeriodic(pollPeriod.toMillis(), unused -> queryContainers());
}
Expand All @@ -185,7 +187,7 @@ void onStop(@Observes ShutdownEvent evt) {
if (!enabled()) {
return;
}
logger.info(String.format("Shutting down %s client", getRealm()));
logger.infov("Shutting down {0} client", getRealm());
vertx.cancelTimer(timerId);
}

Expand Down Expand Up @@ -352,27 +354,34 @@ public void handleContainerEvent(ContainerSpec desc, EventKind evtKind) {
"PORT", // "AnnotationKey.PORT,
Integer.toString(jmxPort)));

DiscoveryNode node = DiscoveryNode.target(target);
DiscoveryNode node = DiscoveryNode.target(target, BaseNodeType.JVM);
target.discoveryNode = node;
String podName = desc.PodName;
if (StringUtils.isNotBlank(podName)) {
DiscoveryNode pod = DiscoveryNode.environment(podName, DiscoveryNode.POD);
DiscoveryNode pod =
DiscoveryNode.environment(podName, ContainerDiscoveryNodeType.POD);
if (!realm.children.contains(pod)) {
pod.children.add(node);
node.parent = pod;
realm.children.add(pod);
pod.parent = realm;
} else {
pod =
DiscoveryNode.getChild(
realm,
n ->
podName.equals(n.name)
&& DiscoveryNode.POD.equals(n.nodeType))
&& ContainerDiscoveryNodeType.POD
.getKind()
.equals(n.nodeType))
.orElseThrow();
pod.children.add(node);
node.parent = pod;
}
pod.persist();
} else {
realm.children.add(node);
node.parent = realm;
}
target.persist();
node.persist();
Expand All @@ -381,11 +390,13 @@ public void handleContainerEvent(ContainerSpec desc, EventKind evtKind) {
Target t = Target.getTargetByConnectUrl(connectUrl);
String podName = desc.PodName;
if (StringUtils.isNotBlank(podName)) {
DiscoveryNode pod = DiscoveryNode.environment(podName, DiscoveryNode.POD);
DiscoveryNode pod =
DiscoveryNode.environment(podName, ContainerDiscoveryNodeType.POD);
pod.children.remove(t.discoveryNode);
} else {
realm.children.remove(t.discoveryNode);
}
t.discoveryNode.parent = null;
realm.persist();
t.delete();
}
Expand Down Expand Up @@ -420,3 +431,25 @@ static record ContainerDetails(Config Config) {}

static record Config(String Hostname) {}
}

enum ContainerDiscoveryNodeType implements NodeType {
// represents a container pod managed by Podman
POD("Pod"),
;

private final String kind;

ContainerDiscoveryNodeType(String kind) {
this.kind = kind;
}

@Override
public String getKind() {
return kind;
}

@Override
public String toString() {
return getKind();
}
}
7 changes: 5 additions & 2 deletions src/main/java/io/cryostat/discovery/CustomDiscovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ void onStart(@Observes StartupEvent evt) {
DiscoveryNode universe = DiscoveryNode.getUniverse();
if (DiscoveryNode.getRealm(REALM).isEmpty()) {
DiscoveryPlugin plugin = new DiscoveryPlugin();
DiscoveryNode node = DiscoveryNode.environment(REALM, DiscoveryNode.REALM);
DiscoveryNode node = DiscoveryNode.environment(REALM, BaseNodeType.REALM);
plugin.realm = node;
plugin.builtin = true;
universe.children.add(node);
node.parent = universe;
plugin.persist();
universe.persist();
}
Expand Down Expand Up @@ -167,11 +168,12 @@ Response doV2Create(
target.annotations = new Annotations();
target.annotations.cryostat().putAll(Map.of("REALM", REALM));

DiscoveryNode node = DiscoveryNode.target(target);
DiscoveryNode node = DiscoveryNode.target(target, BaseNodeType.JVM);
target.discoveryNode = node;
DiscoveryNode realm = DiscoveryNode.getRealm(REALM).orElseThrow();

realm.children.add(node);
node.parent = realm;
target.persist();
node.persist();
realm.persist();
Expand Down Expand Up @@ -212,6 +214,7 @@ public Response delete(@RestPath long id) throws URISyntaxException {
Target target = Target.find("id", id).singleResult();
DiscoveryNode realm = DiscoveryNode.getRealm(REALM).orElseThrow();
realm.children.remove(target.discoveryNode);
target.discoveryNode.parent = null;
realm.persist();
target.delete();
return Response.noContent().build();
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/io/cryostat/discovery/Discovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ public Response register(@Context RoutingContext ctx, JsonObject body)

// TODO apply URI range validation to the remote address
InetAddress remoteAddress = getRemoteAddress(ctx);

URI location;
DiscoveryPlugin plugin;
if (StringUtils.isNotBlank(pluginId) && StringUtils.isNotBlank(priorToken)) {
Expand All @@ -217,7 +216,7 @@ public Response register(@Context RoutingContext ctx, JsonObject body)
plugin.callback = callbackUri;
plugin.realm =
DiscoveryNode.environment(
requireNonBlank(realmName, "realm"), DiscoveryNode.REALM);
requireNonBlank(realmName, "realm"), BaseNodeType.REALM);
plugin.builtin = false;
plugin.persist();

Expand Down
40 changes: 30 additions & 10 deletions src/main/java/io/cryostat/discovery/DiscoveryNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import io.cryostat.targets.Target;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonView;
Expand All @@ -38,6 +39,8 @@
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.PostPersist;
Expand All @@ -55,9 +58,6 @@
public class DiscoveryNode extends PanacheEntity {

public static final String NODE_TYPE = "nodeType";
public static final String UNIVERSE = "Universe";
public static final String REALM = "Realm";
public static final String POD = "Pod";

@Column(unique = false, nullable = false, updatable = false)
@JsonView(Views.Flat.class)
Expand All @@ -74,11 +74,17 @@ public class DiscoveryNode extends PanacheEntity {
@JsonView(Views.Flat.class)
public Map<String, String> labels = new HashMap<>();

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

@Nullable
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parentNode")
@JsonIgnore
public DiscoveryNode parent;

@OneToOne(
mappedBy = "discoveryNode",
cascade = {CascadeType.ALL},
Expand All @@ -94,10 +100,15 @@ public int hashCode() {
return Objects.hash(id, name, nodeType, labels, children, target);
}

public boolean hasChildren() {
return !children.isEmpty();
}

public static DiscoveryNode getUniverse() {
return DiscoveryNode.find(NODE_TYPE, UNIVERSE)
return DiscoveryNode.find(NODE_TYPE, BaseNodeType.UNIVERSE.getKind())
.<DiscoveryNode>singleResultOptional()
.orElseGet(() -> environment(UNIVERSE, UNIVERSE));
.orElseGet(
() -> environment(BaseNodeType.UNIVERSE.toString(), BaseNodeType.UNIVERSE));
}

public static Optional<DiscoveryNode> getRealm(String name) {
Expand All @@ -109,21 +120,30 @@ public static Optional<DiscoveryNode> getChild(
return node.children.stream().filter(predicate).findFirst();
}

public static DiscoveryNode environment(String name, String nodeType) {
public static Optional<DiscoveryNode> getNode(Predicate<DiscoveryNode> predicate) {
List<DiscoveryNode> nodes = listAll();
return nodes.stream().filter(predicate).findFirst();
}

public static List<DiscoveryNode> findAllByNodeType(NodeType nodeType) {
return DiscoveryNode.find(DiscoveryNode.NODE_TYPE, nodeType.getKind()).list();
}

public static DiscoveryNode environment(String name, NodeType nodeType) {
DiscoveryNode node = new DiscoveryNode();
node.name = name;
node.nodeType = nodeType;
node.nodeType = nodeType.getKind();
node.labels = new HashMap<>();
node.children = new ArrayList<>();
node.target = null;
node.persist();
return node;
}

public static DiscoveryNode target(Target target) {
public static DiscoveryNode target(Target target, NodeType nodeType) {
DiscoveryNode node = new DiscoveryNode();
node.name = target.connectUrl.toString();
node.nodeType = "JVM";
node.nodeType = nodeType.getKind();
node.labels = new HashMap<>(target.labels);
node.children = null;
node.target = target;
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/io/cryostat/discovery/JDPDiscovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ void onStart(@Observes StartupEvent evt) {
DiscoveryNode universe = DiscoveryNode.getUniverse();
if (DiscoveryNode.getRealm(REALM).isEmpty()) {
DiscoveryPlugin plugin = new DiscoveryPlugin();
DiscoveryNode node = DiscoveryNode.environment(REALM, DiscoveryNode.REALM);
DiscoveryNode node = DiscoveryNode.environment(REALM, BaseNodeType.REALM);
plugin.realm = node;
plugin.builtin = true;
universe.children.add(node);
node.parent = universe;
plugin.persist();
universe.persist();
}
Expand Down Expand Up @@ -139,17 +140,19 @@ public synchronized void handleJdpEvent(JvmDiscoveryEvent evt) {
"PORT", // "AnnotationKey.PORT,
Integer.toString(rmiTarget.getPort())));

DiscoveryNode node = DiscoveryNode.target(target);
DiscoveryNode node = DiscoveryNode.target(target, BaseNodeType.JVM);

target.discoveryNode = node;
realm.children.add(node);
node.parent = realm;
target.persist();
node.persist();
realm.persist();
break;
case LOST:
Target t = Target.getTargetByConnectUrl(connectUrl);
realm.children.remove(t.discoveryNode);
t.discoveryNode.parent = null;
realm.persist();
t.delete();
break;
Expand Down
Loading
Loading