✨ Huge changes
This commit is contained in:
parent
dc6354f033
commit
61c62738b5
1
.gitignore
vendored
1
.gitignore
vendored
@ -43,3 +43,4 @@ nb-configuration.xml
|
|||||||
/.quarkus/cli/plugins/
|
/.quarkus/cli/plugins/
|
||||||
# TLS Certificates
|
# TLS Certificates
|
||||||
.certs/
|
.certs/
|
||||||
|
/src/main/resources/dev/
|
||||||
|
|||||||
@ -105,6 +105,8 @@ COPY target/quarkus-app/quarkus/ /deployments/quarkus/
|
|||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
|
RUN sudo chmod -R 777 /var/lib/kubooboo
|
||||||
|
|
||||||
USER quarkus
|
USER quarkus
|
||||||
|
|
||||||
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0"
|
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0"
|
||||||
|
|||||||
9
pg-docker-compose.yaml
Normal file
9
pg-docker-compose.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres
|
||||||
|
restart: always
|
||||||
|
shm_size: 128mb
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
ports:
|
||||||
|
- "6666:5432"
|
||||||
16
pom.xml
16
pom.xml
@ -65,6 +65,22 @@
|
|||||||
<artifactId>kubernetes-httpclient-vertx</artifactId>
|
<artifactId>kubernetes-httpclient-vertx</artifactId>
|
||||||
<version>7.3.1</version>
|
<version>7.3.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-scheduler</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Hibernate ORM specific dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-orm-panache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JDBC driver dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-jdbc-postgresql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package dev.dinauer;
|
package dev.dinauer;
|
||||||
|
|
||||||
|
import dev.dinauer.monitoring.nodes.NodeStats;
|
||||||
import dev.dinauer.utils.ClientProvider;
|
import dev.dinauer.utils.ClientProvider;
|
||||||
import io.fabric8.kubernetes.api.model.Node;
|
import io.fabric8.kubernetes.api.model.Node;
|
||||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||||
@ -83,10 +84,6 @@ public class NodeResource
|
|||||||
throw new RuntimeException("Failed to retrieve top nodes.");
|
throw new RuntimeException("Failed to retrieve top nodes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public record NodeStats(Node node, Integer absoluteCpuUsage, Integer relativeCpuUsage, Integer totalCpu, Integer absoluteMemory, Integer relativeMemory, Integer totalMemory)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private Integer extractInteger(String input)
|
private Integer extractInteger(String input)
|
||||||
{
|
{
|
||||||
return Integer.valueOf(input.replace("m", "").replace("%", ""));
|
return Integer.valueOf(input.replace("m", "").replace("%", ""));
|
||||||
|
|||||||
44
src/main/java/dev/dinauer/ProcessRunner.java
Normal file
44
src/main/java/dev/dinauer/ProcessRunner.java
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package dev.dinauer;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class ProcessRunner
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
|
public String run(String command) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
LOG.infof("Running command: %s", command);
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(command.split("\\s+"));
|
||||||
|
pb.redirectErrorStream(true);
|
||||||
|
|
||||||
|
Process p = pb.start();
|
||||||
|
|
||||||
|
List<String> text = new ArrayList<>();
|
||||||
|
try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())))
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
while((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
text.add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int exitCode = p.waitFor();
|
||||||
|
if(exitCode == 0)
|
||||||
|
{
|
||||||
|
return String.join("\n", text);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Error executing command: " + command);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,14 +6,19 @@ import jakarta.inject.Inject;
|
|||||||
import jakarta.ws.rs.*;
|
import jakarta.ws.rs.*;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import io.quarkus.elytron.security.common.BcryptUtil;
|
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Path("/login")
|
@Path("/login")
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
public class LoginResource
|
public class LoginResource
|
||||||
{
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
UserRepo userRepo;
|
UserRepo userRepo;
|
||||||
|
|
||||||
@ -22,11 +27,18 @@ public class LoginResource
|
|||||||
@Produces(MediaType.TEXT_PLAIN)
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
public String login(Login login) throws IOException
|
public String login(Login login) throws IOException
|
||||||
{
|
{
|
||||||
User user = userRepo.findByUsername(login.username());
|
Optional<User> userOptional = userRepo.findOptionalByUsername(login.username());
|
||||||
if(BcryptUtil.matches(login.password(), user.password()))
|
if(userOptional.isPresent())
|
||||||
{
|
{
|
||||||
return Jwt.upn(user.username()).expiresAt(ZonedDateTime.now().plusDays(15).toInstant()).groups(user.roles()).sign();
|
User user = userOptional.get();
|
||||||
|
if(BcryptUtil.matches(login.password(), user.password()))
|
||||||
|
{
|
||||||
|
return Jwt.upn(user.username()).expiresAt(ZonedDateTime.now().plusDays(15).toInstant()).groups(user.roles()).sign();
|
||||||
|
}
|
||||||
|
LOG.info("Cannot access user. Forbidden");
|
||||||
|
throw new ForbiddenException();
|
||||||
}
|
}
|
||||||
throw new ForbiddenException();
|
LOG.info("User not found");
|
||||||
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/main/java/dev/dinauer/monitoring/MonitoredNode.java
Normal file
10
src/main/java/dev/dinauer/monitoring/MonitoredNode.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package dev.dinauer.monitoring;
|
||||||
|
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexCollection;
|
||||||
|
import io.fabric8.kubernetes.api.model.Node;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record MonitoredNode(Node node, List<IndexCollection> jobs)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package dev.dinauer.monitoring;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.Pod;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record MonitoredResource<E, T>(E resource, List<T> jobs)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package dev.dinauer.monitoring;
|
||||||
|
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringConfig;
|
||||||
|
import dev.dinauer.monitoring.entity.repo.MonitoringRepo;
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexCollection;
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexMetricsRepo;
|
||||||
|
import dev.dinauer.monitoring.indexing.TimeUnit;
|
||||||
|
import io.fabric8.kubernetes.api.model.Pod;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Path("/monitorings/{monitoring-id}/jobs")
|
||||||
|
public class MonitoringJobResource
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
MonitoringRepo monitoringRepo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MonitoringService monitoringService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
IndexMetricsRepo indexMetricsRepo;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
public List<MonitoredResource<Pod, IndexCollection>> get(@PathParam("monitoring-id") String monitoringId) throws IOException
|
||||||
|
{
|
||||||
|
List<MonitoredResource<Pod, IndexCollection>> result = new ArrayList<>();
|
||||||
|
MonitoringConfig config = monitoringRepo.findById(monitoringId);
|
||||||
|
List<Pod> pods = monitoringService.findRunningPodsByMonitoringConfig(config);
|
||||||
|
for (Pod pod : pods)
|
||||||
|
{
|
||||||
|
result.add(new MonitoredResource<>(pod, indexMetricsRepo.findByResourceAndMetricAndTimeUnit(String.format("POD-%s", pod.getMetadata().getUid()), config.getType().toString(), TimeUnit.RAW)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/main/java/dev/dinauer/monitoring/MonitoringJobRunner.java
Normal file
102
src/main/java/dev/dinauer/monitoring/MonitoringJobRunner.java
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package dev.dinauer.monitoring;
|
||||||
|
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringConfig;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringType;
|
||||||
|
import dev.dinauer.monitoring.entity.repo.MonitoringRepo;
|
||||||
|
import dev.dinauer.monitoring.log.Log;
|
||||||
|
import dev.dinauer.monitoring.log.LogRepo;
|
||||||
|
import dev.dinauer.monitoring.memory.MemoryMonitoringJobRunner;
|
||||||
|
import dev.dinauer.monitoring.nodes.NodeMonitoringService;
|
||||||
|
import dev.dinauer.monitoring.volume.VolumeMonitoringJobRunner;
|
||||||
|
import dev.dinauer.monitoring.volume.utils.Duration;
|
||||||
|
import io.quarkus.runtime.Startup;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Startup
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MonitoringJobRunner
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
VolumeMonitoringJobRunner volumeMonitoringJobRunner;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MemoryMonitoringJobRunner memoryMonitoringJobRunner;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
NodeMonitoringService nodeMonitoringService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MonitoringRepo monitoringRepo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
LogRepo logRepo;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
List<MonitoringConfig> configs = monitoringRepo.listAll();
|
||||||
|
for (MonitoringConfig config : configs)
|
||||||
|
{
|
||||||
|
schedule(config);
|
||||||
|
}
|
||||||
|
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
|
Runnable task = () -> {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nodeMonitoringService.run();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logRepo.persist(Log.init("Failed to node monitoring job"));
|
||||||
|
LOG.error("Failed to node monitoring job");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
scheduler.scheduleAtFixedRate(task, 0, Duration.parse("5m"), TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void schedule(MonitoringConfig config)
|
||||||
|
{
|
||||||
|
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
|
Runnable task = () -> {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
run(config);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logRepo.persist(Log.init(String.format("Monitoring %s failed.", config.getConfigName())));
|
||||||
|
LOG.errorf("Monitoring %s failed.", config.getConfigName());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
scheduler.scheduleAtFixedRate(task, 0, Duration.parse(config.getInterval()), TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void run(MonitoringConfig config) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
LOG.infof("Running %s %s monitoring.", config.getConfigName(), config.getType().toString().toLowerCase());
|
||||||
|
switch (config.getType())
|
||||||
|
{
|
||||||
|
case VOLUME ->
|
||||||
|
{
|
||||||
|
volumeMonitoringJobRunner.run(config);
|
||||||
|
}
|
||||||
|
case MEMORY ->
|
||||||
|
{
|
||||||
|
memoryMonitoringJobRunner.run(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/java/dev/dinauer/monitoring/MonitoringResource.java
Normal file
25
src/main/java/dev/dinauer/monitoring/MonitoringResource.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package dev.dinauer.monitoring;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringConfig;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringType;
|
||||||
|
import dev.dinauer.monitoring.entity.repo.MonitoringRepo;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Path("/monitorings")
|
||||||
|
public class MonitoringResource
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
MonitoringRepo monitoringRepo;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
public List<MonitoringConfig> get() throws JsonProcessingException
|
||||||
|
{
|
||||||
|
return monitoringRepo.listAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/main/java/dev/dinauer/monitoring/MonitoringService.java
Normal file
35
src/main/java/dev/dinauer/monitoring/MonitoringService.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package dev.dinauer.monitoring;
|
||||||
|
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringConfig;
|
||||||
|
import dev.dinauer.monitoring.entity.TargetConfig;
|
||||||
|
import dev.dinauer.service.PodService;
|
||||||
|
import io.fabric8.kubernetes.api.model.Pod;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.jboss.resteasy.reactive.common.NotImplementedYet;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MonitoringService
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
PodService podService;
|
||||||
|
|
||||||
|
public List<Pod> findRunningPodsByMonitoringConfig(MonitoringConfig config)
|
||||||
|
{
|
||||||
|
TargetConfig targetConfig = config.getTargetConfig();
|
||||||
|
switch (targetConfig.getType())
|
||||||
|
{
|
||||||
|
case LABELS ->
|
||||||
|
{
|
||||||
|
return podService.findByLabels(targetConfig.getNamespace(), targetConfig.getLabels()).stream().filter(pod -> pod.getStatus().getPhase().equals("Running")).toList();
|
||||||
|
}
|
||||||
|
case DEPLOYMENT, STATEFUL_SET ->
|
||||||
|
{
|
||||||
|
throw new NotImplementedYet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Invalid monitoring config type");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package dev.dinauer.monitoring;
|
||||||
|
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexCollection;
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexMetric;
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexMetricsRepo;
|
||||||
|
import dev.dinauer.monitoring.indexing.TimeUnit;
|
||||||
|
import dev.dinauer.utils.ClientProvider;
|
||||||
|
import io.fabric8.kubernetes.api.model.Node;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.QueryParam;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Path("/monitorings/nodes/jobs")
|
||||||
|
public class NodeMonitoringJobResource
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
IndexMetricsRepo indexMetricsRepo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ClientProvider clientProvider;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
public List<MonitoredResource<Node, IndexCollection>> get(@QueryParam("from") ZonedDateTime from, @QueryParam("to") ZonedDateTime to) throws IOException
|
||||||
|
{
|
||||||
|
List<MonitoredResource<Node, IndexCollection>> result = new ArrayList<>();
|
||||||
|
List<Node> nodes = clientProvider.getClient().nodes().list().getItems();
|
||||||
|
for (Node node : nodes)
|
||||||
|
{
|
||||||
|
String resource = String.format("NODE-%s", node.getMetadata().getUid());
|
||||||
|
result.add(new MonitoredResource<>(node, indexMetricsRepo.findByResourceAndMetricAndTimeUnit(resource, "NODE_METRICS", determineTimeUnit(from, to))));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TimeUnit determineTimeUnit(ZonedDateTime from, ZonedDateTime to)
|
||||||
|
{
|
||||||
|
long day = 60 * 60 * 24;
|
||||||
|
long twoDays = day * 2;
|
||||||
|
long fifteenDays = day * 15;
|
||||||
|
|
||||||
|
long dif = to.toEpochSecond() - from.toEpochSecond();
|
||||||
|
if (dif < twoDays)
|
||||||
|
{
|
||||||
|
return TimeUnit.RAW;
|
||||||
|
}
|
||||||
|
if (dif < fifteenDays)
|
||||||
|
{
|
||||||
|
return TimeUnit.HOUR;
|
||||||
|
}
|
||||||
|
return TimeUnit.DAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/main/java/dev/dinauer/monitoring/entity/CpuConfig.java
Normal file
53
src/main/java/dev/dinauer/monitoring/entity/CpuConfig.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package dev.dinauer.monitoring.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "cpu_config")
|
||||||
|
public class CpuConfig
|
||||||
|
{
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(name = "container_name")
|
||||||
|
private String containerName;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "config_id")
|
||||||
|
@JsonIgnore
|
||||||
|
private MonitoringConfig config;
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CpuConfig setId(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContainerName()
|
||||||
|
{
|
||||||
|
return containerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CpuConfig setContainerName(String containerName)
|
||||||
|
{
|
||||||
|
this.containerName = containerName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig getConfig()
|
||||||
|
{
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CpuConfig setConfig(MonitoringConfig config)
|
||||||
|
{
|
||||||
|
this.config = config;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package dev.dinauer.monitoring.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "healthcheck_config")
|
||||||
|
public class HealthcheckConfig
|
||||||
|
{
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "config_id")
|
||||||
|
@JsonIgnore
|
||||||
|
private MonitoringConfig config;
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HealthcheckConfig setId(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig getConfig()
|
||||||
|
{
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HealthcheckConfig setConfig(MonitoringConfig config)
|
||||||
|
{
|
||||||
|
this.config = config;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
package dev.dinauer.monitoring.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "monitoring_config")
|
||||||
|
public class MonitoringConfig
|
||||||
|
{
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(name = "config_name")
|
||||||
|
private String configName;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private MonitoringType type;
|
||||||
|
|
||||||
|
private String interval;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "config")
|
||||||
|
private TargetConfig targetConfig;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "config")
|
||||||
|
private CpuConfig cpuConfig;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "config")
|
||||||
|
private HealthcheckConfig healthcheckConfig;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "config")
|
||||||
|
private VolumeConfig volumeConfig;
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setId(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConfigName()
|
||||||
|
{
|
||||||
|
return configName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setConfigName(String configName)
|
||||||
|
{
|
||||||
|
this.configName = configName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringType getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setType(MonitoringType type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInterval()
|
||||||
|
{
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setInterval(String interval)
|
||||||
|
{
|
||||||
|
this.interval = interval;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig getTargetConfig()
|
||||||
|
{
|
||||||
|
return targetConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setTargetConfig(TargetConfig targetConfig)
|
||||||
|
{
|
||||||
|
this.targetConfig = targetConfig;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CpuConfig getCpuConfig()
|
||||||
|
{
|
||||||
|
return cpuConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setCpuConfig(CpuConfig cpuConfig)
|
||||||
|
{
|
||||||
|
this.cpuConfig = cpuConfig;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HealthcheckConfig getHealthcheckConfig()
|
||||||
|
{
|
||||||
|
return healthcheckConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setHealthcheckConfig(HealthcheckConfig healthcheckConfig)
|
||||||
|
{
|
||||||
|
this.healthcheckConfig = healthcheckConfig;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeConfig getVolumeConfig()
|
||||||
|
{
|
||||||
|
return volumeConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig setVolumeConfig(VolumeConfig volumeConfig)
|
||||||
|
{
|
||||||
|
this.volumeConfig = volumeConfig;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package dev.dinauer.monitoring.entity;
|
||||||
|
|
||||||
|
public enum MonitoringTargetType
|
||||||
|
{
|
||||||
|
DEPLOYMENT,
|
||||||
|
STATEFUL_SET,
|
||||||
|
LABELS
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package dev.dinauer.monitoring.entity;
|
||||||
|
|
||||||
|
public enum MonitoringType
|
||||||
|
{
|
||||||
|
VOLUME, CPU, MEMORY, HEALTHCHECK
|
||||||
|
}
|
||||||
135
src/main/java/dev/dinauer/monitoring/entity/TargetConfig.java
Normal file
135
src/main/java/dev/dinauer/monitoring/entity/TargetConfig.java
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package dev.dinauer.monitoring.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "target_config")
|
||||||
|
public class TargetConfig
|
||||||
|
{
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private MonitoringTargetType type;
|
||||||
|
|
||||||
|
private String namespace;
|
||||||
|
|
||||||
|
@Column(name = "deployment_name")
|
||||||
|
private String deploymentName;
|
||||||
|
|
||||||
|
@Column(name = "stateful_set_name")
|
||||||
|
private String statefulSetName;
|
||||||
|
|
||||||
|
private String labels;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "config_id")
|
||||||
|
@JsonIgnore
|
||||||
|
private MonitoringConfig config;
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig setId(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringTargetType getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig setType(MonitoringTargetType type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNamespace()
|
||||||
|
{
|
||||||
|
return namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig setNamespace(String namespace)
|
||||||
|
{
|
||||||
|
this.namespace = namespace;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeploymentName()
|
||||||
|
{
|
||||||
|
return deploymentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig setDeploymentName(String deploymentName)
|
||||||
|
{
|
||||||
|
this.deploymentName = deploymentName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatefulSetName()
|
||||||
|
{
|
||||||
|
return statefulSetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig setStatefulSetName(String statefulSetName)
|
||||||
|
{
|
||||||
|
this.statefulSetName = statefulSetName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getLabels()
|
||||||
|
{
|
||||||
|
if (labels != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return OBJECT_MAPPER.readValue(labels, new TypeReference<Map<String, String>>() {});
|
||||||
|
}
|
||||||
|
catch (JsonProcessingException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Cannot read labels for target config.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig setLabels(Map<String, String> labels)
|
||||||
|
{
|
||||||
|
if (labels != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.labels = OBJECT_MAPPER.writeValueAsString(labels);
|
||||||
|
}
|
||||||
|
catch (JsonProcessingException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Cannot set labels for target config.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig getConfig()
|
||||||
|
{
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetConfig setConfig(MonitoringConfig config)
|
||||||
|
{
|
||||||
|
this.config = config;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
package dev.dinauer.monitoring.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "volume_config")
|
||||||
|
public class VolumeConfig
|
||||||
|
{
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(name = "mount_path")
|
||||||
|
private String mountPath;
|
||||||
|
|
||||||
|
@Column(name = "container_name")
|
||||||
|
private String containerName;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "config_id")
|
||||||
|
@JsonIgnore
|
||||||
|
private MonitoringConfig config;
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeConfig setId(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoringConfig getConfig()
|
||||||
|
{
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeConfig setConfig(MonitoringConfig config)
|
||||||
|
{
|
||||||
|
this.config = config;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMountPath()
|
||||||
|
{
|
||||||
|
return mountPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeConfig setMountPath(String mountPath)
|
||||||
|
{
|
||||||
|
this.mountPath = mountPath;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContainerName()
|
||||||
|
{
|
||||||
|
return containerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeConfig setContainerName(String containerName)
|
||||||
|
{
|
||||||
|
this.containerName = containerName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package dev.dinauer.monitoring.entity.repo;
|
||||||
|
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringConfig;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringType;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
||||||
|
import io.quarkus.panache.common.Parameters;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MonitoringRepo implements PanacheRepositoryBase<MonitoringConfig, String>
|
||||||
|
{
|
||||||
|
public List<MonitoringConfig> findByMonitoringType(MonitoringType type)
|
||||||
|
{
|
||||||
|
return list("type = :type", Parameters.with("type", type));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package dev.dinauer.monitoring.indexing;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "metrics_index")
|
||||||
|
public class IndexCollection
|
||||||
|
{
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String resource;
|
||||||
|
|
||||||
|
private String metric;
|
||||||
|
|
||||||
|
private String timestamp;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private TimeUnit unit;
|
||||||
|
|
||||||
|
private String metrics;
|
||||||
|
|
||||||
|
public IndexCollection()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexCollection(String resource, String metric, String timestamp, TimeUnit unit)
|
||||||
|
{
|
||||||
|
this.id = UUID.randomUUID().toString();
|
||||||
|
this.resource = resource;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.unit = unit;
|
||||||
|
this.metric = metric;
|
||||||
|
this.metrics = "{}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(String key, long value)
|
||||||
|
{
|
||||||
|
Map<String, IndexMetric> metrics = getMetrics();
|
||||||
|
IndexMetric metric = metrics.get(key);
|
||||||
|
if (metric != null)
|
||||||
|
{
|
||||||
|
metric.add(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IndexMetric newMetric = new IndexMetric();
|
||||||
|
newMetric.add(value);
|
||||||
|
metrics.put(key, newMetric);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.metrics = OBJECT_MAPPER.writeValueAsString(metrics);
|
||||||
|
}
|
||||||
|
catch (JsonProcessingException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calculateAverage(long sum, int count)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return sum * 1.0 / count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimestamp()
|
||||||
|
{
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMetric()
|
||||||
|
{
|
||||||
|
return metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeUnit getUnit()
|
||||||
|
{
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResource()
|
||||||
|
{
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, IndexMetric> getMetrics()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return OBJECT_MAPPER.readValue(metrics, new TypeReference<Map<String, IndexMetric>>() {});
|
||||||
|
}
|
||||||
|
catch (JsonProcessingException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package dev.dinauer.monitoring.indexing;
|
||||||
|
|
||||||
|
public class IndexMetric
|
||||||
|
{
|
||||||
|
private int count;
|
||||||
|
private long sum;
|
||||||
|
private double average;
|
||||||
|
|
||||||
|
public IndexMetric()
|
||||||
|
{
|
||||||
|
this.count = 0;
|
||||||
|
this.sum = 0;
|
||||||
|
this.average = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(long value)
|
||||||
|
{
|
||||||
|
count = count + 1;
|
||||||
|
sum = sum + value;
|
||||||
|
average = calculateAverage(sum, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calculateAverage(long sum, int count)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return sum * 1.0 / count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount()
|
||||||
|
{
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSum()
|
||||||
|
{
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getAverage()
|
||||||
|
{
|
||||||
|
return average;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package dev.dinauer.monitoring.indexing;
|
||||||
|
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
||||||
|
import io.quarkus.panache.common.Parameters;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class IndexMetricsRepo implements PanacheRepositoryBase<IndexCollection, String>
|
||||||
|
{
|
||||||
|
public Optional<IndexCollection> findByProperties(String resource, String metric, String timestamp, TimeUnit unit)
|
||||||
|
{
|
||||||
|
return find("resource = :resource AND metric = :metric AND timestamp = :timestamp AND unit = :unit", Parameters.with("resource", resource).and("metric", metric).and("timestamp", timestamp).and("unit", unit)).firstResultOptional();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IndexCollection> findByResourceAndMetricAndTimeUnit(String resource, String metric, TimeUnit unit)
|
||||||
|
{
|
||||||
|
return list("resource = :resource AND metric = :metric AND unit = :unit ORDER BY timestamp ASC", Parameters.with("resource", resource).and("metric", metric).and("unit", unit));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package dev.dinauer.monitoring.indexing;
|
||||||
|
|
||||||
|
import io.quarkus.runtime.Startup;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Startup
|
||||||
|
@ApplicationScoped
|
||||||
|
public class IndexingService
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
IndexMetricsRepo indexMetricsRepo;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void index(String resource, String metric, Map<String, Long> values)
|
||||||
|
{
|
||||||
|
for (TimeUnit unit : TimeUnit.values())
|
||||||
|
{
|
||||||
|
String timestamp = TimestampGenerator.generateTimestamp(ZonedDateTime.now(Clock.systemUTC()), unit);
|
||||||
|
IndexCollection metrics = indexMetricsRepo.findByProperties(resource, metric, timestamp, unit).orElse(new IndexCollection(resource, metric, timestamp, unit));
|
||||||
|
for (Map.Entry<String, Long> entry : values.entrySet())
|
||||||
|
{
|
||||||
|
metrics.add(entry.getKey().toUpperCase(), entry.getValue());
|
||||||
|
}
|
||||||
|
indexMetricsRepo.persist(metrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package dev.dinauer.monitoring.indexing;
|
||||||
|
|
||||||
|
public enum TimeUnit
|
||||||
|
{
|
||||||
|
RAW, HOUR, DAY
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package dev.dinauer.monitoring.indexing;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
|
public class TimestampGenerator
|
||||||
|
{
|
||||||
|
public static String generateTimestamp(ZonedDateTime timestamp, TimeUnit unit)
|
||||||
|
{
|
||||||
|
switch (unit)
|
||||||
|
{
|
||||||
|
case TimeUnit.RAW ->
|
||||||
|
{
|
||||||
|
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 19);
|
||||||
|
}
|
||||||
|
case TimeUnit.HOUR ->
|
||||||
|
{
|
||||||
|
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 13);
|
||||||
|
}
|
||||||
|
case TimeUnit.DAY ->
|
||||||
|
{
|
||||||
|
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Cannot index by chono unit " + unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/main/java/dev/dinauer/monitoring/log/Log.java
Normal file
60
src/main/java/dev/dinauer/monitoring/log/Log.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package dev.dinauer.monitoring.log;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "log")
|
||||||
|
public class Log
|
||||||
|
{
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
private String message;
|
||||||
|
private ZonedDateTime timestamp;
|
||||||
|
|
||||||
|
public static Log init(String message)
|
||||||
|
{
|
||||||
|
Log log = new Log();
|
||||||
|
log.setId(UUID.randomUUID().toString());
|
||||||
|
log.setMessage(message);
|
||||||
|
log.setTimestamp(ZonedDateTime.now());
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Log setId(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage()
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Log setMessage(String message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZonedDateTime getTimestamp()
|
||||||
|
{
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Log setTimestamp(ZonedDateTime timestamp)
|
||||||
|
{
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/main/java/dev/dinauer/monitoring/log/LogRepo.java
Normal file
9
src/main/java/dev/dinauer/monitoring/log/LogRepo.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package dev.dinauer.monitoring.log;
|
||||||
|
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class LogRepo implements PanacheRepositoryBase<Log, String>
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package dev.dinauer.monitoring.memory;
|
||||||
|
|
||||||
|
import com.cronutils.utils.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ByteExtractor
|
||||||
|
{
|
||||||
|
public static long extractBytes(String input)
|
||||||
|
{
|
||||||
|
String[] sections = input.split("\n");
|
||||||
|
if (sections.length == 2)
|
||||||
|
{
|
||||||
|
String metricsLine = sections[1];
|
||||||
|
List<String> metrics = Arrays.stream(metricsLine.split("\\s+")).filter(text -> !text.isBlank()).toList();
|
||||||
|
if (metrics.size() == 3)
|
||||||
|
{
|
||||||
|
return convertToBytes(metrics.get(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long convertToBytes(String input)
|
||||||
|
{
|
||||||
|
if (input.endsWith("Ki"))
|
||||||
|
{
|
||||||
|
return Long.parseLong(input.replace("Ki", "")) * 1024;
|
||||||
|
}
|
||||||
|
if (input.endsWith("Mi"))
|
||||||
|
{
|
||||||
|
return Long.parseLong(input.replace("Mi", "")) * 1024 * 1024;
|
||||||
|
}
|
||||||
|
if (input.endsWith("Gi"))
|
||||||
|
{
|
||||||
|
return Long.parseLong(input.replace("Gi", "")) * 1024 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNumeric(input))
|
||||||
|
{
|
||||||
|
return Long.parseLong(input);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Invalid byte representation.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package dev.dinauer.monitoring.memory;
|
||||||
|
|
||||||
|
import dev.dinauer.ProcessRunner;
|
||||||
|
import dev.dinauer.monitoring.MonitoringService;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringConfig;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringType;
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexingService;
|
||||||
|
import io.fabric8.kubernetes.api.model.Pod;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MemoryMonitoringJobRunner
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
ProcessRunner processRunner;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MonitoringService monitoringService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
IndexingService indexingService;
|
||||||
|
|
||||||
|
public void run(MonitoringConfig config) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
List<Pod> pods = monitoringService.findRunningPodsByMonitoringConfig(config);
|
||||||
|
|
||||||
|
for (Pod pod : pods)
|
||||||
|
{
|
||||||
|
String podId = pod.getMetadata().getUid();
|
||||||
|
String podName = pod.getMetadata().getName();
|
||||||
|
String result = processRunner.run(String.format("kubectl top pod %s -n %s", podName, config.getTargetConfig().getNamespace()));
|
||||||
|
indexingService.index(String.format("POD-%s", podId), MonitoringType.MEMORY.toString(), Map.ofEntries(Map.entry("CPU", ByteExtractor.extractBytes(result))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
package dev.dinauer.monitoring.nodes;
|
||||||
|
|
||||||
|
import dev.dinauer.ProcessRunner;
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexingService;
|
||||||
|
import dev.dinauer.utils.ClientProvider;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class NodeMonitoringService
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
ClientProvider clientProvider;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ProcessRunner processRunner;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
IndexingService indexingService;
|
||||||
|
|
||||||
|
public void run() throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
List<NodeStats> result = new ArrayList<>();
|
||||||
|
|
||||||
|
String[] stats = getTopNodes().split("\n");
|
||||||
|
|
||||||
|
for(String nodeName : stats)
|
||||||
|
{
|
||||||
|
String[] parts = nodeName.split("\\s+");
|
||||||
|
if(parts.length == 5)
|
||||||
|
{
|
||||||
|
String name = parts[0];
|
||||||
|
String node = clientProvider.getClient().nodes().withName(name).get().getMetadata().getUid();
|
||||||
|
int absoluteCpu = extractInteger(parts[1]);
|
||||||
|
int relativeCpu = extractInteger(parts[2]);
|
||||||
|
int absoluteMemory = extractMemory(parts[3]);
|
||||||
|
int relativeMemory = extractInteger(parts[4]);
|
||||||
|
Map<String, Long> metrics = Map.ofEntries(
|
||||||
|
Map.entry("RELATIVE_CPU", (long) relativeCpu),
|
||||||
|
Map.entry("RELATIVE_MEMORY", (long) relativeMemory),
|
||||||
|
Map.entry("ABSOLUTE_MEMORY", (long) absoluteMemory));
|
||||||
|
indexingService.index(String.format("NODE-%s", node), "NODE_METRICS", metrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTopNodes() throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
String command = String.format("kubectl --kubeconfig=%s top nodes --no-headers", clientProvider.pathToKubeconfig());
|
||||||
|
return processRunner.run(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer extractInteger(String input)
|
||||||
|
{
|
||||||
|
return Integer.valueOf(input.replace("m", "").replace("%", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer extractMemory(String input)
|
||||||
|
{
|
||||||
|
if(input.contains("Ki"))
|
||||||
|
{
|
||||||
|
return Integer.parseInt(input.replace("Ki", ""));
|
||||||
|
}
|
||||||
|
if(input.contains("Mi"))
|
||||||
|
{
|
||||||
|
return Integer.parseInt(input.replace("Mi", "")) * 1024;
|
||||||
|
}
|
||||||
|
if(input.contains("Gi"))
|
||||||
|
{
|
||||||
|
return Integer.parseInt(input.replace("Gi", "")) * 1024 * 1024;
|
||||||
|
}
|
||||||
|
return Integer.parseInt(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package dev.dinauer.monitoring.nodes;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.Node;
|
||||||
|
|
||||||
|
public record NodeStats(Node node, Integer absoluteCpuUsage, Integer relativeCpuUsage, Integer totalCpu, Integer absoluteMemory, Integer relativeMemory, Integer totalMemory)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package dev.dinauer.monitoring.volume;
|
||||||
|
|
||||||
|
public record UsageMetrics(long total, long used, int percentage)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
package dev.dinauer.monitoring.volume;
|
||||||
|
|
||||||
|
import dev.dinauer.ProcessRunner;
|
||||||
|
import dev.dinauer.monitoring.MonitoringService;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringConfig;
|
||||||
|
import dev.dinauer.monitoring.entity.MonitoringType;
|
||||||
|
import dev.dinauer.monitoring.indexing.IndexingService;
|
||||||
|
import io.fabric8.kubernetes.api.model.Pod;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class VolumeMonitoringJobRunner
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ProcessRunner processRunner;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MonitoringService monitoringService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
VolumeUsageRepo volumeUsageRepo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
IndexingService indexingService;
|
||||||
|
|
||||||
|
public void run(MonitoringConfig monitoring) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
List<Pod> pods = monitoringService.findRunningPodsByMonitoringConfig(monitoring);
|
||||||
|
|
||||||
|
for (Pod pod : pods)
|
||||||
|
{
|
||||||
|
String podId = pod.getMetadata().getUid();
|
||||||
|
String podName = pod.getMetadata().getName();
|
||||||
|
if (pod.getStatus().getPhase().equals("Running"))
|
||||||
|
{
|
||||||
|
String result = processRunner.run(String.format("kubectl exec -i %s -c %s -n %s -- df -B1 --output=size,used,avail,pcent -h %s -B1", podName, monitoring.getVolumeConfig().getContainerName(), monitoring.getTargetConfig().getNamespace(), monitoring.getVolumeConfig().getMountPath()));
|
||||||
|
UsageMetrics usage = extractUsage(result);
|
||||||
|
volumeUsageRepo.persist(new VolumeUsage(UUID.randomUUID().toString(), monitoring.getId(), podId, podName, monitoring.getTargetConfig().getNamespace(), ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS), usage));
|
||||||
|
indexingService.index(String.format("POD-%s", podId), MonitoringType.VOLUME.toString(), Map.ofEntries(Map.entry("VOLUME", (long) usage.percentage())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private UsageMetrics extractUsage(String result)
|
||||||
|
{
|
||||||
|
String[] sections = result.split("\n");
|
||||||
|
if (sections.length == 2)
|
||||||
|
{
|
||||||
|
String metrics = sections[1];
|
||||||
|
List<String> metricsSections = Arrays.stream(metrics.split("\\s+")).filter(metric -> !metric.isBlank()).toList();
|
||||||
|
if (metricsSections.size() == 4)
|
||||||
|
{
|
||||||
|
long total = Long.parseLong(metricsSections.get(0));
|
||||||
|
long used = Long.parseLong(metricsSections.get(1));
|
||||||
|
int percentage = Integer.parseInt(metricsSections.get(3).replace("%", ""));
|
||||||
|
return new UsageMetrics(total, used, percentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Cannot extract usage.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package dev.dinauer.monitoring.volume;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
public record VolumeUsage(String id, String monitoringId, String podId, String podName, String namespace, ZonedDateTime timestamp, UsageMetrics metrics)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
package dev.dinauer.monitoring.volume;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import dev.dinauer.WorkdirProvider;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
import org.jboss.resteasy.reactive.common.NotImplementedYet;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class VolumeUsageRepo
|
||||||
|
{
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
WorkdirProvider workdirProvider;
|
||||||
|
|
||||||
|
private Path directory;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void init() throws IOException
|
||||||
|
{
|
||||||
|
Path directory = workdirProvider.getWorkdirPath(Path.of("monitorings", "volumes", "jobs"));
|
||||||
|
Files.createDirectories(directory);
|
||||||
|
this.directory = directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void persist(VolumeUsage usage) throws IOException
|
||||||
|
{
|
||||||
|
Path file = getMonitoringPath(usage.monitoringId()).resolve(usage.podId());
|
||||||
|
Files.write(file, (OBJECT_MAPPER.writeValueAsString(usage) + "\n").getBytes(), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VolumeUsage> findByMonitoringIdAndPodId(String monitoringId, String podId) throws IOException
|
||||||
|
{
|
||||||
|
Path file = getMonitoringPath(monitoringId).resolve(podId);
|
||||||
|
if (Files.exists(file))
|
||||||
|
{
|
||||||
|
List<VolumeUsage> result = new ArrayList<>();
|
||||||
|
for (String line : Files.readAllLines(file, StandardCharsets.UTF_8))
|
||||||
|
{
|
||||||
|
result.add(OBJECT_MAPPER.readValue(line, VolumeUsage.class));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VolumeUsage> findAll(String monitoringId) throws IOException
|
||||||
|
{
|
||||||
|
List<VolumeUsage> result = new ArrayList<>();
|
||||||
|
try (Stream<Path> files = Files.list(getMonitoringPath(monitoringId)))
|
||||||
|
{
|
||||||
|
for (Path file : files.toList())
|
||||||
|
{
|
||||||
|
result.add(OBJECT_MAPPER.readValue(Files.readString(file), VolumeUsage.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path getMonitoringPath(String monitoringId) throws IOException
|
||||||
|
{
|
||||||
|
Path monitoringDirectory = workdirProvider.getWorkdirPath(directory.resolve(monitoringId));
|
||||||
|
Files.createDirectories(monitoringDirectory);
|
||||||
|
return monitoringDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package dev.dinauer.monitoring.volume.utils;
|
||||||
|
|
||||||
|
public class Duration
|
||||||
|
{
|
||||||
|
public static long parse(String input)
|
||||||
|
{
|
||||||
|
if (input.length() > 1)
|
||||||
|
{
|
||||||
|
char unit = input.charAt(input.length() - 1);
|
||||||
|
long value = Long.parseLong(input.substring(0, input.length() - 1));
|
||||||
|
switch (unit)
|
||||||
|
{
|
||||||
|
case 's' ->
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case 'm' ->
|
||||||
|
{
|
||||||
|
return value * 60;
|
||||||
|
}
|
||||||
|
case 'h' ->
|
||||||
|
{
|
||||||
|
return value * 60 * 60;
|
||||||
|
}
|
||||||
|
default ->
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(String.format("Invalid unit %s", unit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Invalid input");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,13 +2,16 @@ package dev.dinauer.service;
|
|||||||
|
|
||||||
import dev.dinauer.utils.ClientProvider;
|
import dev.dinauer.utils.ClientProvider;
|
||||||
import io.fabric8.kubernetes.api.model.Pod;
|
import io.fabric8.kubernetes.api.model.Pod;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.StatefulSet;
|
||||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||||
|
import io.fabric8.kubernetes.client.dsl.AppsAPIGroupDSL;
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
@ -22,6 +25,24 @@ public class PodService
|
|||||||
return clientProvider.getClient().pods().inNamespace(namespace).list().getItems();
|
return clientProvider.getClient().pods().inNamespace(namespace).list().getItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Pod> findByStatefulSet(String name, String namespace)
|
||||||
|
{
|
||||||
|
try(AppsAPIGroupDSL apps = clientProvider.getClient().apps())
|
||||||
|
{
|
||||||
|
StatefulSet set = apps.statefulSets().inNamespace(namespace).withName(name).get();
|
||||||
|
if (set != null)
|
||||||
|
{
|
||||||
|
return findByLabels(namespace, set.getSpec().getSelector().getMatchLabels());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Pod> findByLabels(String namespace, Map<String, String> labels)
|
||||||
|
{
|
||||||
|
return clientProvider.getClient().pods().inNamespace(namespace).withLabels(labels).list().getItems();
|
||||||
|
}
|
||||||
|
|
||||||
public List<Pod> findAll()
|
public List<Pod> findAll()
|
||||||
{
|
{
|
||||||
return clientProvider.getClient().pods().inAnyNamespace().list().getItems();
|
return clientProvider.getClient().pods().inAnyNamespace().list().getItems();
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import io.quarkus.runtime.Startup;
|
|||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -18,6 +19,9 @@ public class StartupService
|
|||||||
private static final String INITIAL_USERNAME = "admin";
|
private static final String INITIAL_USERNAME = "admin";
|
||||||
private static final String INITIAL_PASSWORD = "admin";
|
private static final String INITIAL_PASSWORD = "admin";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
UserRepo userRepo;
|
UserRepo userRepo;
|
||||||
|
|
||||||
@ -27,6 +31,7 @@ public class StartupService
|
|||||||
if(userRepo.findOptionalByUsername(INITIAL_USERNAME).isEmpty())
|
if(userRepo.findOptionalByUsername(INITIAL_USERNAME).isEmpty())
|
||||||
{
|
{
|
||||||
userRepo.persist(buildInitialUser());
|
userRepo.persist(buildInitialUser());
|
||||||
|
LOG.infof("Initialized user 'admin'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,12 +5,19 @@ quarkus.http.root-path=/api
|
|||||||
|
|
||||||
dev.dinauer.kobooboo.kubeconfigs.dir=/var/lib/kubooboo/config
|
dev.dinauer.kobooboo.kubeconfigs.dir=/var/lib/kubooboo/config
|
||||||
dev.dinauer.kubooboo.work.dir=/var/lib/kubooboo/work
|
dev.dinauer.kubooboo.work.dir=/var/lib/kubooboo/work
|
||||||
%dev.dev.dinauer.kobooboo.kubeconfigs.dir=C:\\Users\\andre\\.kube\\config
|
%dev.dev.dinauer.kobooboo.kubeconfigs.dir=/home/andreas/.kube/config
|
||||||
%dev.dev.dinauer.kubooboo.work.dir=C:\\Users\\andre\\Documents\\dev\\kubeman\\backend\\src\\main\\resources\\dev
|
%dev.dev.dinauer.kubooboo.work.dir=/home/andreas/Documents/dev/kubooboo/backend/src/main/resources/dev
|
||||||
|
|
||||||
# Keys
|
# Keys
|
||||||
%prod.smallrye.jwt.sign.key.location=/etc/kubooboo/keys/privateKey.pem
|
%prod.smallrye.jwt.sign.key.location=${PRIVATE_KEY_LOCATION}
|
||||||
%prod.mp.jwt.verify.publickey.location=/etc/kubooboo/keys/publicKey.pem
|
%prod.mp.jwt.verify.publickey.location=${PUBLIC_KEY_LOCATION}
|
||||||
# Keys Dev
|
# Keys Dev
|
||||||
%dev.smallrye.jwt.sign.key.location=privateKey.pem
|
%dev.smallrye.jwt.sign.key.location=privateKey.pem
|
||||||
%dev.mp.jwt.verify.publickey.location=publicKey.pem
|
%dev.mp.jwt.verify.publickey.location=publicKey.pem
|
||||||
|
|
||||||
|
# Postgres
|
||||||
|
%dev.quarkus.datasource.db-kind = postgresql
|
||||||
|
%dev.quarkus.datasource.username = postgres
|
||||||
|
%dev.quarkus.datasource.password = postgres
|
||||||
|
%dev.quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:6666/postgres
|
||||||
|
%dev,test.quarkus.hibernate-orm.schema-management.strategy = none
|
||||||
11
src/main/resources/import.sql
Normal file
11
src/main/resources/import.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
INSERT INTO monitoring_config (id, config_name, type, interval)
|
||||||
|
VALUES ('5da234f4-3a34-4b1c-b72a-7330ca3b1dcf', 'Postgres Cluster', 'VOLUME', '30s');
|
||||||
|
INSERT INTO target_config (id, type, namespace, labels, deployment_name, stateful_set_name, config_id)
|
||||||
|
VALUES ('4bd2f449-ed11-4f3f-830a-e4dc39cb21f5', 'LABELS', 'tavolio-prod', '{"cnpg.io/cluster":"postgres-cluster"}', null, null, '5da234f4-3a34-4b1c-b72a-7330ca3b1dcf');
|
||||||
|
INSERT INTO volume_config (id, container_name, mount_path, config_id)
|
||||||
|
VALUES ('4090a60c-4517-4d76-b460-a0454014f30d', 'postgres', '/var/lib/postgresql/data', '5da234f4-3a34-4b1c-b72a-7330ca3b1dcf');
|
||||||
|
|
||||||
|
INSERT INTO monitoring_config (id, config_name, type, interval)
|
||||||
|
VALUES ('2da234f4-3a34-4b1c-b72a-7330ca3b1dcf', 'Postgres Cluster', 'MEMORY', '40s');
|
||||||
|
INSERT INTO target_config (id, type, namespace, labels, deployment_name, stateful_set_name, config_id)
|
||||||
|
VALUES ('2bd2f449-ed11-4f3f-830a-e4dc39cb21f5', 'LABELS', 'tavolio-prod', '{"cnpg.io/cluster":"postgres-cluster"}', null, null, '2da234f4-3a34-4b1c-b72a-7330ca3b1dcf');
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package dev.dinauer.monitoring.memory;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class ByteExtractorTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
String input = """
|
||||||
|
NAME CPU(cores) MEMORY(bytes)
|
||||||
|
postgres-cluster-1 13m 50Mi
|
||||||
|
""";
|
||||||
|
|
||||||
|
long bytes = ByteExtractor.extractBytes(input);
|
||||||
|
|
||||||
|
assertEquals(52428800, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user