feat(monitoring): ajout du referentiel Baserow infra_versions et du workflow n8n veille-versions-stack
This commit is contained in:
@@ -0,0 +1,831 @@
|
||||
{
|
||||
"id": "zUWN5K4Q1A2JKFIS",
|
||||
"name": "veille-versions-stack",
|
||||
"description": null,
|
||||
"active": true,
|
||||
"activeVersionId": "c2da509a-651c-4fa9-9aa8-00f4ab440123",
|
||||
"createdAt": "2026-08-21T19:10:15.587Z",
|
||||
"updatedAt": "2026-08-21T19:16:24.466Z",
|
||||
"isArchived": false,
|
||||
"versionId": "c2da509a-651c-4fa9-9aa8-00f4ab440123",
|
||||
"versionCounter": 7,
|
||||
"sourceWorkflowId": null,
|
||||
"triggerCount": 2,
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"field": "weeks",
|
||||
"triggerAtHour": 8,
|
||||
"triggerAtMinute": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "1",
|
||||
"name": "Schedule Trigger (Lundi 08h00)",
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
200,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "http://baserow:80/api/database/rows/table/1097/?user_field_names=true&size=100",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Host",
|
||||
"value": "baserow.bolbol.tn"
|
||||
},
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Token qS5KEYki5sA1VEdCn9hobXk0Bp4jd9fr"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "2",
|
||||
"name": "Lire Table Baserow",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
420,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"command": "all",
|
||||
"authentication": "privateKey"
|
||||
},
|
||||
"id": "3",
|
||||
"name": "SSH Versions NAS (Restreint)",
|
||||
"type": "n8n-nodes-base.ssh",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
640,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"sshPrivateKey": {
|
||||
"id": "UjDRfssNSG2A9Ku9",
|
||||
"name": "SSH n8n-versions-ro"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "\nconst baserowRows = $('Lire Table Baserow').first().json.results;\nconst sshOutput = $input.first().json.stdout;\nlet installedVersions = {};\ntry {\n installedVersions = JSON.parse(sshOutput);\n} catch (e) {\n // fallback parsing\n installedVersions = {};\n}\n\nconst items = [];\nfor (const row of baserowRows) {\n const conteneur = row.conteneur;\n const repo = row.image_repo;\n const installed = installedVersions[conteneur] || row.version_installee;\n const statutObj = row.statut;\n const currentStatut = typeof statutObj === 'object' && statutObj !== null ? statutObj.value : statutObj;\n const criticiteObj = row.criticite;\n const criticite = typeof criticiteObj === 'object' && criticiteObj !== null ? criticiteObj.value : criticiteObj;\n\n items.push({\n json: {\n id: row.id,\n conteneur: conteneur,\n image_repo: repo,\n methode_verif: typeof row.methode_verif === 'object' && row.methode_verif !== null ? row.methode_verif.value : row.methode_verif,\n version_installee: installed,\n current_disponible: row.derniere_version_disponible,\n current_statut: currentStatut,\n criticite: criticite,\n notes: row.notes || ''\n }\n });\n}\nreturn items;\n"
|
||||
},
|
||||
"id": "4",
|
||||
"name": "Pr\u00e9parer \u00c9l\u00e9ments & Mapping",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
860,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "=https://hub.docker.com/v2/repositories/{{ $json.image_repo }}/tags?page_size=25&ordering=last_updated",
|
||||
"options": {}
|
||||
},
|
||||
"id": "5",
|
||||
"name": "API Docker Hub",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1080,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "\nconst origItem = $('Pr\u00e9parer \u00c9l\u00e9ments & Mapping').item.json;\nconst dockerHubData = $input.item.json;\nconst tagResults = dockerHubData.results || [];\nconst repo = origItem.image_repo;\nconst installed = String(origItem.version_installee || '');\nconst currentStatut = origItem.current_statut;\n\n// Helper: extract best stable tag\nlet candidateTags = [];\nfor (const t of tagResults) {\n const name = t.name;\n if (!name) continue;\n if (/(next|beta|dev|nightly|rc|alpha|test|latest|stable|edge|canary|master|main|^alpine$|^lts$)/i.test(name)) continue;\n if (/sha-[0-9a-f]+/i.test(name)) continue;\n \n if (repo === 'gitea/gitea') {\n if (!/^[0-9]+\\.[0-9]+\\.[0-9]+-rootless$/.test(name)) continue;\n } else if (repo === 'vaultwarden/server') {\n if (!/^[0-9]+\\.[0-9]+\\.[0-9]+-alpine$/.test(name)) continue;\n } else if (repo === 'portainer/portainer-ce') {\n if (!/^[0-9]+\\.[0-9]+\\.[0-9]+$/.test(name)) continue;\n } else if (['n8nio/n8n', 'crowdsecurity/crowdsec', 'tailscale/tailscale', 'baserow/baserow', 'triliumnext/trilium'].includes(repo)) {\n if (!/^[v]?[0-9]+\\.[0-9]+\\.[0-9]+$/.test(name)) continue;\n }\n\n candidateTags.push(name);\n}\n\nconst latestAvailable = candidateTags.length > 0 ? candidateTags[0] : (origItem.current_disponible || installed);\n\n// Normaliser pour comparaison\nlet cleanInstalled = installed.replace(/^v/, '');\nlet cleanAvailable = latestAvailable.replace(/^v/, '');\n\nlet isUpToDate = (installed === latestAvailable) || (cleanInstalled === cleanAvailable);\nif (installed.includes('image 14/05/2026')) {\n isUpToDate = false;\n}\n\nlet newStatut = '\u00c0 jour';\nlet ecart = '0';\n\nif (currentStatut === 'En pause') {\n newStatut = 'En pause';\n ecart = isUpToDate ? '0' : '\u00c0 confirmer';\n} else if (!isUpToDate) {\n newStatut = 'Retard mineur';\n ecart = 'Install\u00e9e: ' + installed + ' \u2794 Dispo: ' + latestAvailable;\n}\n\nconst today = new Date().toISOString().split('T')[0];\nconst shouldAlert = (newStatut !== '\u00c0 jour') && (newStatut !== 'En pause') && (currentStatut === '\u00c0 jour');\n\nreturn [{\n json: {\n id: origItem.id,\n conteneur: origItem.conteneur,\n image_repo: origItem.image_repo,\n version_installee: installed,\n derniere_version_disponible: latestAvailable,\n ecart: ecart,\n statut: newStatut,\n date_derniere_verification: today,\n criticite: origItem.criticite,\n should_alert: shouldAlert\n }\n}];\n"
|
||||
},
|
||||
"id": "6",
|
||||
"name": "Analyser \u00c9carts & Versions",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1300,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "PATCH",
|
||||
"url": "=http://baserow:80/api/database/rows/table/1097/{{ $json.id }}/?user_field_names=true",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Host",
|
||||
"value": "baserow.bolbol.tn"
|
||||
},
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Token qS5KEYki5sA1VEdCn9hobXk0Bp4jd9fr"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"bodyParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "version_installee",
|
||||
"value": "={{ $json.version_installee }}"
|
||||
},
|
||||
{
|
||||
"name": "derniere_version_disponible",
|
||||
"value": "={{ $json.derniere_version_disponible }}"
|
||||
},
|
||||
{
|
||||
"name": "ecart",
|
||||
"value": "={{ $json.ecart }}"
|
||||
},
|
||||
{
|
||||
"name": "statut",
|
||||
"value": "={{ $json.statut }}"
|
||||
},
|
||||
{
|
||||
"name": "date_derniere_verification",
|
||||
"value": "={{ $json.date_derniere_verification }}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "7",
|
||||
"name": "Mettre \u00e0 Jour Baserow",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1520,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "\nconst allItems = $('Analyser \u00c9carts & Versions').all();\nconst alertItems = allItems.filter(i => i.json.should_alert || i.json.force_alert);\n\nif (alertItems.length === 0) {\n return [{ json: { no_alert: true, message: 'Aucun nouvel ecart' } }];\n}\n\nlet msg = '\ud83d\udd14 *Veille Versions Stack NAS \u2014 D\u00e9tection d\\'\u00e9carts*\\n\\n';\nfor (const item of alertItems) {\n const j = item.json;\n msg += '\u2022 *' + j.conteneur + '* (' + j.criticite + ') : `' + j.version_installee + '` \u2794 `' + j.derniere_version_disponible + '`\\n';\n}\nmsg += '\\n\ud83d\udccb *R\u00e9f\u00e9rentiel Baserow* : https://baserow.bolbol.tn/database/317/table/1097';\n\nreturn [{\n json: {\n message: msg,\n count: alertItems.length\n }\n}];\n"
|
||||
},
|
||||
"id": "8",
|
||||
"name": "Agr\u00e9ger Alertes",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1740,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"chatId": "2084513684",
|
||||
"text": "={{ $json.message }}",
|
||||
"additionalFields": {
|
||||
"parse_mode": "Markdown"
|
||||
}
|
||||
},
|
||||
"id": "9",
|
||||
"name": "Telegram Notification",
|
||||
"type": "n8n-nodes-base.telegram",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
1960,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"telegramApi": {
|
||||
"id": "OyOHh6jAzCDsiBux",
|
||||
"name": "ND_Telegram"
|
||||
}
|
||||
},
|
||||
"webhookId": "55fcac45-4ff4-488c-ae3f-c7ff8d60ecd0"
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "manual-trigger-1",
|
||||
"name": "When clicking Test workflow",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
200,
|
||||
140
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"path": "test-veille-versions",
|
||||
"responseMode": "lastNode",
|
||||
"options": {}
|
||||
},
|
||||
"id": "webhook-trigger-1",
|
||||
"name": "Webhook Trigger Test",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
200,
|
||||
460
|
||||
],
|
||||
"webhookId": "test-veille-versions"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"boolean": [
|
||||
{
|
||||
"value1": "={{ $json.no_alert }}",
|
||||
"value2": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "filter-node-1",
|
||||
"name": "Filtrer Alertes",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
1850,
|
||||
300
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Schedule Trigger (Lundi 08h00)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Lire Table Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Lire Table Baserow": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "SSH Versions NAS (Restreint)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"SSH Versions NAS (Restreint)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Pr\u00e9parer \u00c9l\u00e9ments & Mapping",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Pr\u00e9parer \u00c9l\u00e9ments & Mapping": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "API Docker Hub",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"API Docker Hub": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Analyser \u00c9carts & Versions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Analyser \u00c9carts & Versions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Mettre \u00e0 Jour Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Mettre \u00e0 Jour Baserow": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Agr\u00e9ger Alertes",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Agr\u00e9ger Alertes": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Filtrer Alertes",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"When clicking Test workflow": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Lire Table Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Webhook Trigger Test": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Lire Table Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Filtrer Alertes": {
|
||||
"main": [
|
||||
[],
|
||||
[
|
||||
{
|
||||
"node": "Telegram Notification",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"nodeGroups": [],
|
||||
"settings": {
|
||||
"executionOrder": "v1",
|
||||
"timezone": "Africa/Tunis"
|
||||
},
|
||||
"staticData": {
|
||||
"node:Schedule Trigger (Lundi 08h00)": {
|
||||
"recurrenceRules": [
|
||||
null
|
||||
],
|
||||
"recurrenceRuleSignatures": [
|
||||
null
|
||||
]
|
||||
}
|
||||
},
|
||||
"pinData": null,
|
||||
"meta": null,
|
||||
"tags": [],
|
||||
"shared": [
|
||||
{
|
||||
"role": "workflow:owner",
|
||||
"workflowId": "zUWN5K4Q1A2JKFIS",
|
||||
"projectId": "3IcTI301RXGOgKWv",
|
||||
"project": {
|
||||
"id": "3IcTI301RXGOgKWv",
|
||||
"name": "Nabil Derouiche <contact@bolbol.tn>",
|
||||
"type": "personal",
|
||||
"icon": null,
|
||||
"description": null,
|
||||
"customTelemetryTags": [],
|
||||
"creatorId": "809184e1-fa99-4ef9-95d5-047b8b7c225e",
|
||||
"createdAt": "2025-11-22T16:04:26.142Z",
|
||||
"updatedAt": "2025-11-22T17:22:23.186Z"
|
||||
},
|
||||
"createdAt": "2026-08-21T19:10:15.587Z",
|
||||
"updatedAt": "2026-08-21T19:10:15.587Z"
|
||||
}
|
||||
],
|
||||
"activeVersion": {
|
||||
"versionId": "c2da509a-651c-4fa9-9aa8-00f4ab440123",
|
||||
"workflowId": "zUWN5K4Q1A2JKFIS",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"field": "weeks",
|
||||
"triggerAtHour": 8,
|
||||
"triggerAtMinute": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "1",
|
||||
"name": "Schedule Trigger (Lundi 08h00)",
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
200,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "http://baserow:80/api/database/rows/table/1097/?user_field_names=true&size=100",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Host",
|
||||
"value": "baserow.bolbol.tn"
|
||||
},
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Token qS5KEYki5sA1VEdCn9hobXk0Bp4jd9fr"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "2",
|
||||
"name": "Lire Table Baserow",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
420,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"command": "all",
|
||||
"authentication": "privateKey"
|
||||
},
|
||||
"id": "3",
|
||||
"name": "SSH Versions NAS (Restreint)",
|
||||
"type": "n8n-nodes-base.ssh",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
640,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"sshPrivateKey": {
|
||||
"id": "UjDRfssNSG2A9Ku9",
|
||||
"name": "SSH n8n-versions-ro"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "\nconst baserowRows = $('Lire Table Baserow').first().json.results;\nconst sshOutput = $input.first().json.stdout;\nlet installedVersions = {};\ntry {\n installedVersions = JSON.parse(sshOutput);\n} catch (e) {\n // fallback parsing\n installedVersions = {};\n}\n\nconst items = [];\nfor (const row of baserowRows) {\n const conteneur = row.conteneur;\n const repo = row.image_repo;\n const installed = installedVersions[conteneur] || row.version_installee;\n const statutObj = row.statut;\n const currentStatut = typeof statutObj === 'object' && statutObj !== null ? statutObj.value : statutObj;\n const criticiteObj = row.criticite;\n const criticite = typeof criticiteObj === 'object' && criticiteObj !== null ? criticiteObj.value : criticiteObj;\n\n items.push({\n json: {\n id: row.id,\n conteneur: conteneur,\n image_repo: repo,\n methode_verif: typeof row.methode_verif === 'object' && row.methode_verif !== null ? row.methode_verif.value : row.methode_verif,\n version_installee: installed,\n current_disponible: row.derniere_version_disponible,\n current_statut: currentStatut,\n criticite: criticite,\n notes: row.notes || ''\n }\n });\n}\nreturn items;\n"
|
||||
},
|
||||
"id": "4",
|
||||
"name": "Pr\u00e9parer \u00c9l\u00e9ments & Mapping",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
860,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "=https://hub.docker.com/v2/repositories/{{ $json.image_repo }}/tags?page_size=25&ordering=last_updated",
|
||||
"options": {}
|
||||
},
|
||||
"id": "5",
|
||||
"name": "API Docker Hub",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1080,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "\nconst origItem = $('Pr\u00e9parer \u00c9l\u00e9ments & Mapping').item.json;\nconst dockerHubData = $input.item.json;\nconst tagResults = dockerHubData.results || [];\nconst repo = origItem.image_repo;\nconst installed = String(origItem.version_installee || '');\nconst currentStatut = origItem.current_statut;\n\n// Helper: extract best stable tag\nlet candidateTags = [];\nfor (const t of tagResults) {\n const name = t.name;\n if (!name) continue;\n if (/(next|beta|dev|nightly|rc|alpha|test|latest|stable|edge|canary|master|main|^alpine$|^lts$)/i.test(name)) continue;\n if (/sha-[0-9a-f]+/i.test(name)) continue;\n \n if (repo === 'gitea/gitea') {\n if (!/^[0-9]+\\.[0-9]+\\.[0-9]+-rootless$/.test(name)) continue;\n } else if (repo === 'vaultwarden/server') {\n if (!/^[0-9]+\\.[0-9]+\\.[0-9]+-alpine$/.test(name)) continue;\n } else if (repo === 'portainer/portainer-ce') {\n if (!/^[0-9]+\\.[0-9]+\\.[0-9]+$/.test(name)) continue;\n } else if (['n8nio/n8n', 'crowdsecurity/crowdsec', 'tailscale/tailscale', 'baserow/baserow', 'triliumnext/trilium'].includes(repo)) {\n if (!/^[v]?[0-9]+\\.[0-9]+\\.[0-9]+$/.test(name)) continue;\n }\n\n candidateTags.push(name);\n}\n\nconst latestAvailable = candidateTags.length > 0 ? candidateTags[0] : (origItem.current_disponible || installed);\n\n// Normaliser pour comparaison\nlet cleanInstalled = installed.replace(/^v/, '');\nlet cleanAvailable = latestAvailable.replace(/^v/, '');\n\nlet isUpToDate = (installed === latestAvailable) || (cleanInstalled === cleanAvailable);\nif (installed.includes('image 14/05/2026')) {\n isUpToDate = false;\n}\n\nlet newStatut = '\u00c0 jour';\nlet ecart = '0';\n\nif (currentStatut === 'En pause') {\n newStatut = 'En pause';\n ecart = isUpToDate ? '0' : '\u00c0 confirmer';\n} else if (!isUpToDate) {\n newStatut = 'Retard mineur';\n ecart = 'Install\u00e9e: ' + installed + ' \u2794 Dispo: ' + latestAvailable;\n}\n\nconst today = new Date().toISOString().split('T')[0];\nconst shouldAlert = (newStatut !== '\u00c0 jour') && (newStatut !== 'En pause') && (currentStatut === '\u00c0 jour');\n\nreturn [{\n json: {\n id: origItem.id,\n conteneur: origItem.conteneur,\n image_repo: origItem.image_repo,\n version_installee: installed,\n derniere_version_disponible: latestAvailable,\n ecart: ecart,\n statut: newStatut,\n date_derniere_verification: today,\n criticite: origItem.criticite,\n should_alert: shouldAlert\n }\n}];\n"
|
||||
},
|
||||
"id": "6",
|
||||
"name": "Analyser \u00c9carts & Versions",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1300,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "PATCH",
|
||||
"url": "=http://baserow:80/api/database/rows/table/1097/{{ $json.id }}/?user_field_names=true",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Host",
|
||||
"value": "baserow.bolbol.tn"
|
||||
},
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Token qS5KEYki5sA1VEdCn9hobXk0Bp4jd9fr"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"bodyParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "version_installee",
|
||||
"value": "={{ $json.version_installee }}"
|
||||
},
|
||||
{
|
||||
"name": "derniere_version_disponible",
|
||||
"value": "={{ $json.derniere_version_disponible }}"
|
||||
},
|
||||
{
|
||||
"name": "ecart",
|
||||
"value": "={{ $json.ecart }}"
|
||||
},
|
||||
{
|
||||
"name": "statut",
|
||||
"value": "={{ $json.statut }}"
|
||||
},
|
||||
{
|
||||
"name": "date_derniere_verification",
|
||||
"value": "={{ $json.date_derniere_verification }}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "7",
|
||||
"name": "Mettre \u00e0 Jour Baserow",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1520,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "\nconst allItems = $('Analyser \u00c9carts & Versions').all();\nconst alertItems = allItems.filter(i => i.json.should_alert || i.json.force_alert);\n\nif (alertItems.length === 0) {\n return [{ json: { no_alert: true, message: 'Aucun nouvel ecart' } }];\n}\n\nlet msg = '\ud83d\udd14 *Veille Versions Stack NAS \u2014 D\u00e9tection d\\'\u00e9carts*\\n\\n';\nfor (const item of alertItems) {\n const j = item.json;\n msg += '\u2022 *' + j.conteneur + '* (' + j.criticite + ') : `' + j.version_installee + '` \u2794 `' + j.derniere_version_disponible + '`\\n';\n}\nmsg += '\\n\ud83d\udccb *R\u00e9f\u00e9rentiel Baserow* : https://baserow.bolbol.tn/database/317/table/1097';\n\nreturn [{\n json: {\n message: msg,\n count: alertItems.length\n }\n}];\n"
|
||||
},
|
||||
"id": "8",
|
||||
"name": "Agr\u00e9ger Alertes",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1740,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"chatId": "2084513684",
|
||||
"text": "={{ $json.message }}",
|
||||
"additionalFields": {
|
||||
"parse_mode": "Markdown"
|
||||
}
|
||||
},
|
||||
"id": "9",
|
||||
"name": "Telegram Notification",
|
||||
"type": "n8n-nodes-base.telegram",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
1960,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"telegramApi": {
|
||||
"id": "OyOHh6jAzCDsiBux",
|
||||
"name": "ND_Telegram"
|
||||
}
|
||||
},
|
||||
"webhookId": "55fcac45-4ff4-488c-ae3f-c7ff8d60ecd0"
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "manual-trigger-1",
|
||||
"name": "When clicking Test workflow",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
200,
|
||||
140
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"path": "test-veille-versions",
|
||||
"responseMode": "lastNode",
|
||||
"options": {}
|
||||
},
|
||||
"id": "webhook-trigger-1",
|
||||
"name": "Webhook Trigger Test",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
200,
|
||||
460
|
||||
],
|
||||
"webhookId": "test-veille-versions"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"boolean": [
|
||||
{
|
||||
"value1": "={{ $json.no_alert }}",
|
||||
"value2": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "filter-node-1",
|
||||
"name": "Filtrer Alertes",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
1850,
|
||||
300
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Schedule Trigger (Lundi 08h00)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Lire Table Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Lire Table Baserow": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "SSH Versions NAS (Restreint)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"SSH Versions NAS (Restreint)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Pr\u00e9parer \u00c9l\u00e9ments & Mapping",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Pr\u00e9parer \u00c9l\u00e9ments & Mapping": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "API Docker Hub",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"API Docker Hub": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Analyser \u00c9carts & Versions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Analyser \u00c9carts & Versions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Mettre \u00e0 Jour Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Mettre \u00e0 Jour Baserow": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Agr\u00e9ger Alertes",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Agr\u00e9ger Alertes": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Filtrer Alertes",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"When clicking Test workflow": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Lire Table Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Webhook Trigger Test": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Lire Table Baserow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Filtrer Alertes": {
|
||||
"main": [
|
||||
[],
|
||||
[
|
||||
{
|
||||
"node": "Telegram Notification",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"nodeGroups": [],
|
||||
"authors": "Nabil Derouiche",
|
||||
"name": null,
|
||||
"description": null,
|
||||
"autosaved": false,
|
||||
"createdAt": "2026-08-21T19:16:24.469Z",
|
||||
"updatedAt": "2026-08-21T19:16:24.469Z",
|
||||
"workflowPublishHistory": [
|
||||
{
|
||||
"id": 337,
|
||||
"workflowId": "zUWN5K4Q1A2JKFIS",
|
||||
"versionId": "c2da509a-651c-4fa9-9aa8-00f4ab440123",
|
||||
"event": "activated",
|
||||
"userId": "809184e1-fa99-4ef9-95d5-047b8b7c225e",
|
||||
"createdAt": "2026-08-21T19:16:30.446Z"
|
||||
},
|
||||
{
|
||||
"id": 338,
|
||||
"workflowId": "zUWN5K4Q1A2JKFIS",
|
||||
"versionId": "c2da509a-651c-4fa9-9aa8-00f4ab440123",
|
||||
"event": "deactivated",
|
||||
"userId": "809184e1-fa99-4ef9-95d5-047b8b7c225e",
|
||||
"createdAt": "2026-08-21T19:16:30.834Z"
|
||||
},
|
||||
{
|
||||
"id": 339,
|
||||
"workflowId": "zUWN5K4Q1A2JKFIS",
|
||||
"versionId": "c2da509a-651c-4fa9-9aa8-00f4ab440123",
|
||||
"event": "activated",
|
||||
"userId": "809184e1-fa99-4ef9-95d5-047b8b7c225e",
|
||||
"createdAt": "2026-08-21T19:16:31.044Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user