mirror of
https://github.com/9technologygroup/patchmon.net.git
synced 2025-11-13 18:36:01 +00:00
357 lines
10 KiB
JavaScript
357 lines
10 KiB
JavaScript
const express = require("express");
|
|
const { getPrismaClient } = require("../config/prisma");
|
|
const { v4: uuidv4 } = require("uuid");
|
|
|
|
const prisma = getPrismaClient();
|
|
const router = express.Router();
|
|
|
|
// POST /api/v1/integrations/docker - Docker data collection endpoint
|
|
router.post("/docker", async (req, res) => {
|
|
try {
|
|
const apiId = req.headers["x-api-id"];
|
|
const apiKey = req.headers["x-api-key"];
|
|
const {
|
|
containers,
|
|
images,
|
|
volumes,
|
|
networks,
|
|
updates,
|
|
daemon_info: _daemon_info,
|
|
hostname,
|
|
machine_id,
|
|
agent_version: _agent_version,
|
|
} = req.body;
|
|
|
|
console.log(
|
|
`[Docker Integration] Received data from ${hostname || machine_id}`,
|
|
);
|
|
|
|
// Validate API credentials
|
|
const host = await prisma.hosts.findFirst({
|
|
where: { api_id: apiId, api_key: apiKey },
|
|
});
|
|
|
|
if (!host) {
|
|
console.warn("[Docker Integration] Invalid API credentials");
|
|
return res.status(401).json({ error: "Invalid API credentials" });
|
|
}
|
|
|
|
console.log(
|
|
`[Docker Integration] Processing for host: ${host.friendly_name}`,
|
|
);
|
|
|
|
const now = new Date();
|
|
|
|
// Helper function to validate and parse dates
|
|
const parseDate = (dateString) => {
|
|
if (!dateString) return now;
|
|
const date = new Date(dateString);
|
|
return Number.isNaN(date.getTime()) ? now : date;
|
|
};
|
|
|
|
let containersProcessed = 0;
|
|
let imagesProcessed = 0;
|
|
let volumesProcessed = 0;
|
|
let networksProcessed = 0;
|
|
let updatesProcessed = 0;
|
|
|
|
// Process containers
|
|
if (containers && Array.isArray(containers)) {
|
|
console.log(
|
|
`[Docker Integration] Processing ${containers.length} containers`,
|
|
);
|
|
for (const containerData of containers) {
|
|
const containerId = uuidv4();
|
|
|
|
// Find or create image
|
|
let imageId = null;
|
|
if (containerData.image_repository && containerData.image_tag) {
|
|
const image = await prisma.docker_images.upsert({
|
|
where: {
|
|
repository_tag_image_id: {
|
|
repository: containerData.image_repository,
|
|
tag: containerData.image_tag,
|
|
image_id: containerData.image_id || "unknown",
|
|
},
|
|
},
|
|
update: {
|
|
last_checked: now,
|
|
updated_at: now,
|
|
},
|
|
create: {
|
|
id: uuidv4(),
|
|
repository: containerData.image_repository,
|
|
tag: containerData.image_tag,
|
|
image_id: containerData.image_id || "unknown",
|
|
source: containerData.image_source || "docker-hub",
|
|
created_at: parseDate(containerData.created_at),
|
|
updated_at: now,
|
|
},
|
|
});
|
|
imageId = image.id;
|
|
}
|
|
|
|
// Upsert container
|
|
await prisma.docker_containers.upsert({
|
|
where: {
|
|
host_id_container_id: {
|
|
host_id: host.id,
|
|
container_id: containerData.container_id,
|
|
},
|
|
},
|
|
update: {
|
|
name: containerData.name,
|
|
image_id: imageId,
|
|
image_name: containerData.image_name,
|
|
image_tag: containerData.image_tag || "latest",
|
|
status: containerData.status,
|
|
state: containerData.state || containerData.status,
|
|
ports: containerData.ports || null,
|
|
started_at: containerData.started_at
|
|
? parseDate(containerData.started_at)
|
|
: null,
|
|
updated_at: now,
|
|
last_checked: now,
|
|
},
|
|
create: {
|
|
id: containerId,
|
|
host_id: host.id,
|
|
container_id: containerData.container_id,
|
|
name: containerData.name,
|
|
image_id: imageId,
|
|
image_name: containerData.image_name,
|
|
image_tag: containerData.image_tag || "latest",
|
|
status: containerData.status,
|
|
state: containerData.state || containerData.status,
|
|
ports: containerData.ports || null,
|
|
created_at: parseDate(containerData.created_at),
|
|
started_at: containerData.started_at
|
|
? parseDate(containerData.started_at)
|
|
: null,
|
|
updated_at: now,
|
|
},
|
|
});
|
|
containersProcessed++;
|
|
}
|
|
}
|
|
|
|
// Process standalone images
|
|
if (images && Array.isArray(images)) {
|
|
console.log(`[Docker Integration] Processing ${images.length} images`);
|
|
for (const imageData of images) {
|
|
await prisma.docker_images.upsert({
|
|
where: {
|
|
repository_tag_image_id: {
|
|
repository: imageData.repository,
|
|
tag: imageData.tag,
|
|
image_id: imageData.image_id,
|
|
},
|
|
},
|
|
update: {
|
|
size_bytes: imageData.size_bytes
|
|
? BigInt(imageData.size_bytes)
|
|
: null,
|
|
digest: imageData.digest || null,
|
|
last_checked: now,
|
|
updated_at: now,
|
|
},
|
|
create: {
|
|
id: uuidv4(),
|
|
repository: imageData.repository,
|
|
tag: imageData.tag,
|
|
image_id: imageData.image_id,
|
|
digest: imageData.digest,
|
|
size_bytes: imageData.size_bytes
|
|
? BigInt(imageData.size_bytes)
|
|
: null,
|
|
source: imageData.source || "docker-hub",
|
|
created_at: parseDate(imageData.created_at),
|
|
updated_at: now,
|
|
},
|
|
});
|
|
imagesProcessed++;
|
|
}
|
|
}
|
|
|
|
// Process volumes
|
|
if (volumes && Array.isArray(volumes)) {
|
|
console.log(`[Docker Integration] Processing ${volumes.length} volumes`);
|
|
for (const volumeData of volumes) {
|
|
await prisma.docker_volumes.upsert({
|
|
where: {
|
|
host_id_volume_id: {
|
|
host_id: host.id,
|
|
volume_id: volumeData.volume_id,
|
|
},
|
|
},
|
|
update: {
|
|
name: volumeData.name,
|
|
driver: volumeData.driver || "local",
|
|
mountpoint: volumeData.mountpoint || null,
|
|
renderer: volumeData.renderer || null,
|
|
scope: volumeData.scope || "local",
|
|
labels: volumeData.labels || null,
|
|
options: volumeData.options || null,
|
|
size_bytes: volumeData.size_bytes
|
|
? BigInt(volumeData.size_bytes)
|
|
: null,
|
|
ref_count: volumeData.ref_count || 0,
|
|
updated_at: now,
|
|
last_checked: now,
|
|
},
|
|
create: {
|
|
id: uuidv4(),
|
|
host_id: host.id,
|
|
volume_id: volumeData.volume_id,
|
|
name: volumeData.name,
|
|
driver: volumeData.driver || "local",
|
|
mountpoint: volumeData.mountpoint || null,
|
|
renderer: volumeData.renderer || null,
|
|
scope: volumeData.scope || "local",
|
|
labels: volumeData.labels || null,
|
|
options: volumeData.options || null,
|
|
size_bytes: volumeData.size_bytes
|
|
? BigInt(volumeData.size_bytes)
|
|
: null,
|
|
ref_count: volumeData.ref_count || 0,
|
|
created_at: parseDate(volumeData.created_at),
|
|
updated_at: now,
|
|
},
|
|
});
|
|
volumesProcessed++;
|
|
}
|
|
}
|
|
|
|
// Process networks
|
|
if (networks && Array.isArray(networks)) {
|
|
console.log(
|
|
`[Docker Integration] Processing ${networks.length} networks`,
|
|
);
|
|
for (const networkData of networks) {
|
|
await prisma.docker_networks.upsert({
|
|
where: {
|
|
host_id_network_id: {
|
|
host_id: host.id,
|
|
network_id: networkData.network_id,
|
|
},
|
|
},
|
|
update: {
|
|
name: networkData.name,
|
|
driver: networkData.driver,
|
|
scope: networkData.scope || "local",
|
|
ipv6_enabled: networkData.ipv6_enabled || false,
|
|
internal: networkData.internal || false,
|
|
attachable:
|
|
networkData.attachable !== undefined
|
|
? networkData.attachable
|
|
: true,
|
|
ingress: networkData.ingress || false,
|
|
config_only: networkData.config_only || false,
|
|
labels: networkData.labels || null,
|
|
ipam: networkData.ipam || null,
|
|
container_count: networkData.container_count || 0,
|
|
updated_at: now,
|
|
last_checked: now,
|
|
},
|
|
create: {
|
|
id: uuidv4(),
|
|
host_id: host.id,
|
|
network_id: networkData.network_id,
|
|
name: networkData.name,
|
|
driver: networkData.driver,
|
|
scope: networkData.scope || "local",
|
|
ipv6_enabled: networkData.ipv6_enabled || false,
|
|
internal: networkData.internal || false,
|
|
attachable:
|
|
networkData.attachable !== undefined
|
|
? networkData.attachable
|
|
: true,
|
|
ingress: networkData.ingress || false,
|
|
config_only: networkData.config_only || false,
|
|
labels: networkData.labels || null,
|
|
ipam: networkData.ipam || null,
|
|
container_count: networkData.container_count || 0,
|
|
created_at: networkData.created_at
|
|
? parseDate(networkData.created_at)
|
|
: null,
|
|
updated_at: now,
|
|
},
|
|
});
|
|
networksProcessed++;
|
|
}
|
|
}
|
|
|
|
// Process updates
|
|
if (updates && Array.isArray(updates)) {
|
|
console.log(`[Docker Integration] Processing ${updates.length} updates`);
|
|
for (const updateData of updates) {
|
|
// Find the image by repository and image_id
|
|
const image = await prisma.docker_images.findFirst({
|
|
where: {
|
|
repository: updateData.repository,
|
|
tag: updateData.current_tag,
|
|
image_id: updateData.image_id,
|
|
},
|
|
});
|
|
|
|
if (image) {
|
|
// Store digest info in changelog_url field as JSON
|
|
const digestInfo = JSON.stringify({
|
|
method: "digest_comparison",
|
|
current_digest: updateData.current_digest,
|
|
available_digest: updateData.available_digest,
|
|
});
|
|
|
|
// Upsert the update record
|
|
await prisma.docker_image_updates.upsert({
|
|
where: {
|
|
image_id_available_tag: {
|
|
image_id: image.id,
|
|
available_tag: updateData.available_tag,
|
|
},
|
|
},
|
|
update: {
|
|
updated_at: now,
|
|
changelog_url: digestInfo,
|
|
severity: "digest_changed",
|
|
},
|
|
create: {
|
|
id: uuidv4(),
|
|
image_id: image.id,
|
|
current_tag: updateData.current_tag,
|
|
available_tag: updateData.available_tag,
|
|
severity: "digest_changed",
|
|
changelog_url: digestInfo,
|
|
updated_at: now,
|
|
},
|
|
});
|
|
updatesProcessed++;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(
|
|
`[Docker Integration] Successfully processed: ${containersProcessed} containers, ${imagesProcessed} images, ${volumesProcessed} volumes, ${networksProcessed} networks, ${updatesProcessed} updates`,
|
|
);
|
|
|
|
res.json({
|
|
message: "Docker data collected successfully",
|
|
containers_received: containersProcessed,
|
|
images_received: imagesProcessed,
|
|
volumes_received: volumesProcessed,
|
|
networks_received: networksProcessed,
|
|
updates_found: updatesProcessed,
|
|
});
|
|
} catch (error) {
|
|
console.error("[Docker Integration] Error collecting Docker data:", error);
|
|
console.error("[Docker Integration] Error stack:", error.stack);
|
|
res.status(500).json({
|
|
error: "Failed to collect Docker data",
|
|
message: error.message,
|
|
details: process.env.NODE_ENV === "development" ? error.stack : undefined,
|
|
});
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|