diff --git a/server/src/domain/checks/check.repository.mongo.ts b/server/src/domain/checks/check.repository.mongo.ts index 9b46f2dbd..b779a2295 100644 --- a/server/src/domain/checks/check.repository.mongo.ts +++ b/server/src/domain/checks/check.repository.mongo.ts @@ -24,6 +24,7 @@ import { getHardwareUpChecks, getHardwareStats, getHardwareTotalChecks } from "@ import { CheckFilter, DateRange } from "@/types/query.js"; import { AppError } from "@/utils/AppError.js"; import { NETWORK_ERROR } from "@/types/network.js"; +import { getDockerLatestCheck, getDockerStats, getDockerTotalChecks, getDockerUpChecks } from "@/domain/checks/check.docker.aggregation.js"; const SERVICE_NAME = "ChecksRepository"; @@ -304,6 +305,9 @@ class MongoChecksRepository implements IChecksRepository { if (options?.type === "pagespeed") { return this.findPageSpeedDateRangeChecks(monitorObjectId, start, end, dateString); } + if (options?.type === "docker") { + return this.findDockerDateRangeChecks(monitorObjectId, start, end, dateString); + } return this.findUptimeDateRangeChecks(options?.type ?? "http", monitorObjectId, start, end, dateString); }; @@ -414,7 +418,7 @@ class MongoChecksRepository implements IChecksRepository { return totalDeleted; }; private findUptimeDateRangeChecks = async ( - monitorType: Exclude, + monitorType: Exclude, monitorObjectId: mongoose.Types.ObjectId, startDate: Date, endDate: Date, @@ -630,6 +634,30 @@ class MongoChecksRepository implements IChecksRepository { groupedChecks: result?.groupedChecks ?? [], }; }; + + private findDockerDateRangeChecks = async (monitorObjectId: mongoose.Types.ObjectId, startDate: Date, endDate: Date, dateString: string) => { + const monitorId = monitorObjectId.toHexString(); + const dates = { start: startDate, end: endDate }; + const [totalChecks, upChecks, aggregate, latestDoc] = await Promise.all([ + getDockerTotalChecks(monitorId, dates), + getDockerUpChecks(monitorId, dates), + getDockerStats(monitorId, dates, dateString), + getDockerLatestCheck(monitorId), + ]); + return { + monitorType: "docker" as const, + aggregateData: { totalChecks: totalChecks ?? 0 }, + upChecks, + aggregate, + latest: latestDoc + ? { + containers: latestDoc.containers ?? [], + summary: latestDoc.containerSummary, + checkedAt: toDateString(latestDoc.createdAt), + } + : null, + }; + }; } export default MongoChecksRepository; diff --git a/server/src/domain/checks/check.type.ts b/server/src/domain/checks/check.type.ts index 77486aa79..00ab3641d 100644 --- a/server/src/domain/checks/check.type.ts +++ b/server/src/domain/checks/check.type.ts @@ -1,7 +1,6 @@ import type { MonitorType } from "@/domain/monitors/monitor.type.js"; import { DockerContainerInfo, DockerContainerSummary } from "@/types/network.js"; import type { Response } from "got"; -import { number } from "zod"; export const CHECK_TTL_SENTINEL = 366; @@ -151,11 +150,10 @@ export interface PageSpeedGroupedCheck { accessibility: number; bestPractices: number; seo: number; - totalChecks: number; } export interface UptimeChecksResult { - monitorType: Exclude; + monitorType: Exclude; groupedChecks: GroupedUptimeCheck[]; groupedUpChecks: GroupedCheck[]; groupedDownChecks: GroupedCheck[]; diff --git a/server/src/domain/monitors/monitor.service.ts b/server/src/domain/monitors/monitor.service.ts index 33b8413db..c0ff1e20f 100644 --- a/server/src/domain/monitors/monitor.service.ts +++ b/server/src/domain/monitors/monitor.service.ts @@ -7,6 +7,7 @@ import type { PageSpeedDetailsResult, GamesMap, GroupedGeoCheckResult, + DockerDetailsResult, } from "@/domain/monitors/monitor.type.js"; import { supportsGeoCheck, supportsUptimeDetails } from "@/domain/monitors/monitor.type.js"; import type { UptimeChecksResult, HardwareChecksResult, PageSpeedChecksResult, DockerChecksResult } from "@/domain/checks/check.type.js"; @@ -40,6 +41,7 @@ export interface IMonitorService { getUptimeDetailsById(args: { teamId: string; monitorId: string; dateRange: DateRange }): Promise; getHardwareDetailsById(args: { teamId: string; monitorId: string; dateRange: DateRange }): Promise; getPageSpeedDetailsById(args: { teamId: string; monitorId: string; dateRange: DateRange }): Promise; + getDockerDetailsById(args: { teamId: string; monitorId: string; dateRange: DateRange }): Promise; getGeoChecksByMonitorId(args: { teamId: string; monitorId: string; @@ -282,6 +284,44 @@ export class MonitorService implements IMonitorService { monitorStats, }; }; + getDockerDetailsById = async ({ + teamId, + monitorId, + dateRange, + }: { + teamId: string; + monitorId: string; + dateRange: DateRange; + }): Promise => { + const monitor = await this.monitorsRepository.findById(monitorId, teamId); + if (!monitor) { + throw new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 }); + } + if (monitor.type !== "docker") { + throw new AppError({ message: `${monitor.type} monitors are not supported for docker details`, status: 400 }); + } + + const checksData = await this.checksRepository.findByDateRangeAndMonitorId(monitor.id, dateRange, { + type: monitor.type, + }); + + if (checksData.monitorType !== "docker") { + throw new AppError({ message: "Unable to load docker stats for this monitor", status: 500 }); + } + + const monitorStats = await this.monitorStatsRepository.findByMonitorId(monitor.id); + + return { + monitor, + stats: { + aggregateData: checksData.aggregateData, + upChecks: checksData.upChecks, + aggregate: checksData.aggregate, + latest: checksData.latest, + }, + monitorStats, + }; + }; getGeoChecksByMonitorId = async ({ teamId,