Files
nas-runbooks/common/workflows/veille-versions-stack.n8n.json
T

431 lines
15 KiB
JSON

{
"name": "veille-versions-stack",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 8
}
]
}
},
"id": "1",
"name": "Schedule Trigger (Lundi 08h00)",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
200,
300
]
},
{
"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": {
"url": "http://baserow-oauth-proxy: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": {
"command": "all",
"authentication": "privateKey"
},
"id": "ssh-vps-node",
"name": "SSH Versions VPS (Restreint)",
"type": "n8n-nodes-base.ssh",
"typeVersion": 1,
"position": [
860,
300
],
"credentials": {
"sshPrivateKey": {
"id": "VpsVersionsSsh01",
"name": "SSH n8n-versions-ro-vps"
}
}
},
{
"parameters": {
"jsCode": "\nconst baserowRows = $('Lire Table Baserow').first().json.results;\nconst sshNasRaw = $('SSH Versions NAS (Restreint)').first()?.json?.stdout || '';\nconst sshVpsRaw = $('SSH Versions VPS (Restreint)').first()?.json?.stdout || '';\n\nlet installedVersions = {};\ntry {\n Object.assign(installedVersions, JSON.parse(sshNasRaw));\n} catch (e) {}\n\ntry {\n Object.assign(installedVersions, JSON.parse(sshVpsRaw));\n} catch (e) {}\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 const methode = typeof row.methode_verif === 'object' && row.methode_verif !== null ? row.methode_verif.value : row.methode_verif;\n const emplacement = typeof row.emplacement === 'object' && row.emplacement !== null ? row.emplacement.value : (row.emplacement || 'NAS');\n\n let apiUrl = '';\n if (methode === 'npm_registry') {\n apiUrl = 'https://registry.npmjs.org/' + encodeURIComponent(repo);\n } else {\n apiUrl = 'https://hub.docker.com/v2/repositories/' + repo + '/tags?page_size=25&ordering=last_updated';\n }\n\n items.push({\n json: {\n id: row.id,\n conteneur: conteneur,\n image_repo: repo,\n methode_verif: methode,\n emplacement: emplacement,\n api_url: apiUrl,\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éparer Éléments & Mapping",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1080,
300
]
},
{
"parameters": {
"url": "={{ $json.api_url }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "User-Agent",
"value": "n8n-veille-versions/1.0"
}
]
},
"options": {}
},
"onError": "continueRegularOutput",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 2000,
"id": "5",
"name": "API Registres (Docker Hub / npm)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1300,
300
]
},
{
"parameters": {
"jsCode": "\nconst origItems = $('Préparer Éléments & Mapping').all();\nconst registryItems = $input.all();\nconst results = [];\n\nfor (let i = 0; i < origItems.length; i++) {\n const origItem = origItems[i].json;\n const registryData = registryItems[i]?.json || {};\n const repo = origItem.image_repo;\n const methode = origItem.methode_verif;\n const installed = String(origItem.version_installee || '');\n const currentStatut = origItem.current_statut;\n\n let latestAvailable = '';\n\n if (methode === 'npm_registry') {\n const distTags = registryData['dist-tags'] || {};\n latestAvailable = distTags.latest || distTags.next || '';\n if (!latestAvailable && registryData.versions) {\n const versions = Object.keys(registryData.versions);\n latestAvailable = versions[versions.length - 1] || '';\n }\n } else {\n const tagResults = registryData.results || [];\n let candidateTags = [];\n for (const t of tagResults) {\n const name = t.name;\n if (!name) continue;\n if (/(beta|dev|nightly|alpha|test|latest|stable|edge|canary|master|main|^alpine$|^lts$|-s6$)/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 (repo === 'filebrowser/filebrowser') {\n if (!/^v?[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 latestAvailable = candidateTags.length > 0 ? candidateTags[0] : (origItem.current_disponible || installed);\n }\n\n if (!latestAvailable) {\n latestAvailable = origItem.current_disponible || installed;\n }\n\n let cleanInstalled = installed.replace(/^v/, '');\n let cleanAvailable = latestAvailable.replace(/^v/, '');\n\n let isUpToDate = (installed === latestAvailable) || (cleanInstalled === cleanAvailable);\n\n let newStatut = jour';\n let ecart = '0';\n\n if (currentStatut === 'En pause') {\n newStatut = 'En pause';\n ecart = isUpToDate ? '0' : confirmer';\n } else if (!isUpToDate) {\n newStatut = 'Retard mineur';\n ecart = 'Installée: ' + installed + ' Dispo: ' + latestAvailable;\n }\n\n const today = new Date().toISOString().split('T')[0];\n const shouldAlert = (newStatut !== jour') && (newStatut !== 'En pause') && (currentStatut === jour');\n\n results.push({\n json: {\n id: origItem.id,\n conteneur: origItem.conteneur,\n image_repo: origItem.image_repo,\n emplacement: origItem.emplacement,\n methode_verif: origItem.methode_verif,\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}\n\nreturn results;\n"
},
"id": "6",
"name": "Analyser Écarts & Versions",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1520,
300
]
},
{
"parameters": {
"method": "PATCH",
"url": "=http://baserow-oauth-proxy: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"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"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": {}
},
"onError": "continueRegularOutput",
"id": "7",
"name": "Mettre à Jour Baserow",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1740,
300
]
},
{
"parameters": {
"jsCode": "\nconst allItems = $('Analyser Écarts & 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 = '🔔 *Veille Versions Stack (NAS & VPS) — Détection d\\'écarts*\\n\\n';\nfor (const item of alertItems) {\n const j = item.json;\n msg += '• *' + j.conteneur + '* [' + j.emplacement + '] (' + j.criticite + ') : `' + j.version_installee + '` ➔ `' + j.derniere_version_disponible + '`\\n';\n}\nmsg += '\\n📋 *Référentiel 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éger Alertes",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1960,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.no_alert }}",
"value2": true
}
]
}
},
"id": "filter-node-1",
"name": "Filtrer Alertes",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
2180,
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": [
2400,
300
],
"credentials": {
"telegramApi": {
"id": "OyOHh6jAzCDsiBux",
"name": "ND_Telegram"
}
}
}
],
"connections": {
"Schedule Trigger (Lundi 08h00)": {
"main": [
[
{
"node": "Lire Table Baserow",
"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
}
]
]
},
"Lire Table Baserow": {
"main": [
[
{
"node": "SSH Versions NAS (Restreint)",
"type": "main",
"index": 0
}
]
]
},
"SSH Versions NAS (Restreint)": {
"main": [
[
{
"node": "SSH Versions VPS (Restreint)",
"type": "main",
"index": 0
}
]
]
},
"SSH Versions VPS (Restreint)": {
"main": [
[
{
"node": "Préparer Éléments & Mapping",
"type": "main",
"index": 0
}
]
]
},
"Préparer Éléments & Mapping": {
"main": [
[
{
"node": "API Registres (Docker Hub / npm)",
"type": "main",
"index": 0
}
]
]
},
"API Registres (Docker Hub / npm)": {
"main": [
[
{
"node": "Analyser Écarts & Versions",
"type": "main",
"index": 0
}
]
]
},
"Analyser Écarts & Versions": {
"main": [
[
{
"node": "Mettre à Jour Baserow",
"type": "main",
"index": 0
}
]
]
},
"Mettre à Jour Baserow": {
"main": [
[
{
"node": "Agréger Alertes",
"type": "main",
"index": 0
}
]
]
},
"Agréger Alertes": {
"main": [
[
{
"node": "Filtrer Alertes",
"type": "main",
"index": 0
}
]
]
},
"Filtrer Alertes": {
"main": [
[],
[
{
"node": "Telegram Notification",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"timezone": "Africa/Tunis"
},
"versionId": "4e4291da-fa65-4d62-bccc-c83dcf0b3944",
"id": "zUWN5K4Q1A2JKFIS"
}