← Tableau de bord

Introduction

Ce système automatise la migration complète de tous les Shared Drives d'un compte Google Workspace (Compte A) vers un autre compte Google Workspace (Compte B), sans interruption de service et avec une reprise sur erreur.

La migration est orchestrée via n8n, exécutée par un agent rclone déployé sur le VPS, et suivie via Google Sheets comme base de données de progression.

Principe fondamental Chaque fichier ou dossier est tracé individuellement avec un statut (EN ATTENTE → EN COURS → TRANSFÉRÉ). En cas d'erreur, le workflow de vérification WF-C détermine si le fichier est réellement absent (vraie erreur) ou bien présent malgré l'erreur rclone (faux positif).

Architecture globale

Vue d'ensemble des composants
graph TB subgraph DA["Google Drive — Compte A (source)"] SD1[("Shared Drives\nsource")] end subgraph N8N["Orchestration n8n"] WF0["WF-0\nCréer drives destination"] WFA["WF-A\nScanner les drives"] WFB["WF-B ⏱\nOrchestrer transferts"] WFC["WF-C ▶\nVérifier erreurs"] end subgraph DATA["Données — Google Sheets"] SH1[("Rapport\nglobal drives")] SH2[("Transfert_Detail\nfichier par fichier")] end subgraph VPS["Infrastructure VPS — rclone_agent :3001"] AGENT["rclone_agent.py\nHTTP API"] RCLONE["rclone binary"] end subgraph DB["Google Drive — Compte B (destination)"] SD2[("Shared Drives\ndestination")] end WF0 -->|crée drives| SD2 WF0 -->|MAJ IDs destination| SH1 SD1 -->|lsjson scan| WFA WFA -->|écrit fichiers EN ATTENTE| SH2 WFB -->|lit EN ATTENTE / EN COURS| SH2 WFB -->|POST /transfer| AGENT AGENT --> RCLONE RCLONE -->|rclone copyto / copy| SD2 RCLONE -->|rclone lsf check| SD2 AGENT -->|status SUCCESS/ERROR| WFB WFB -->|MAJ statuts| SH2 WFB -->|consolide| SH1 WFC -->|lit ERREUR| SH2 WFC -->|POST /check| AGENT WFC -->|MAJ statut vérifié| SH2

Composants

n8n Workflows
docker · n8n.levell.cloud
Orchestrateur principal. 4 workflows (WF-0, WF-A, WF-B, WF-C) coordonnent l'intégralité de la migration via des nœuds Google Sheets et HTTP.
rclone_agent.py
Python · HTTP :3001 · host
Agent HTTP minimal. Expose /transfer, /status, /check, /scan. Lance rclone en arrière-plan et persiste les jobs sur disque.
Google Sheets
Sheets API · OAuth2
Base de données de progression. 2 onglets : Rapport (1 ligne par drive) et Transfert_Detail (1 ligne par fichier/dossier).
rclone
/usr/bin/rclone · Google Drive backend
Outil de copie. Utilise rclone copyto pour les fichiers individuels et rclone copy pour les dossiers. Authentification OAuth2 par compte.

WF-0 · Créer les drives de destination

Exécuté une seule fois avant la migration. Lit la liste des Shared Drives du Compte A depuis le Rapport et crée leur équivalent vide dans le Compte B.

Flux WF-0
flowchart LR T([▶ Manuel]) --> R[Lire Rapport\nShared Drives A] R --> F[Filtrer\nÀ TRANSFÉRER] F --> C[POST /create-drive\nrclone_agent] C --> U[MAJ Rapport\nID destination]
Idempotence Si WF-0 est relancé, il ne recrée pas les drives déjà créés (l'ID destination est déjà rempli dans le Rapport).

WF-A · Scanner les Shared Drives

Pour chaque drive dont le statut est À TRANSFÉRER, appelle POST /scan sur rclone_agent (qui exécute rclone lsjson sur le drive source, profondeur max 2). Chaque élément retourné est inséré dans Transfert_Detail avec le statut EN ATTENTE.

Flux WF-A
flowchart LR T([▶ Manuel]) --> R[Lire Rapport] R --> F[Filtrer\nÀ TRANSFÉRER] F --> S[POST /scan\nrclone lsjson depth=2] S --> P[Aplatir résultats\nfichier + dossier] P --> W[Écrire Transfert_Detail\nstatut EN ATTENTE]

Colonnes générées dans Transfert_Detail

ColonneDescriptionExemple
CléIdentifiant unique NomDrive|CheminMonDrive|Digital/logo.png
CheminChemin relatif dans le driveDigital/logo.png
Typefichier ou dossierfichier
ID sourceID du Shared Drive source0AH…
ID destinationID du Shared Drive destination0AC…
StatutEN ATTENTE au départEN ATTENTE

WF-B · Orchestrateur

Le cœur du système. S'exécute toutes les 5 minutes et lance 3 chaînes en parallèle à chaque tick.

Architecture WF-B — 3 chaînes parallèles
flowchart TB T([⏱ Toutes les 5 min]) --> A1 & B1 & C1 subgraph CA["Chaîne A — Poll statuts"] A1[Lire Sheet] --> A2[Filtrer EN COURS] A2 --> A3[GET /status\npour chaque job] A3 --> A4[Traiter résultats\nSUCCESS / ERROR] A4 --> A5[MAJ Sheet\nTRANSFÉRÉ / ERREUR] end subgraph CB["Chaîne B — Consolider drives"] B1[Lire Sheet] --> B2[Vérifier si drive\n100% TRANSFÉRÉ] B2 --> B3[MAJ Rapport\nDÉJÀ TRANSFÉRÉ] end subgraph CC["Chaîne C — Lancer transfers"] C1[Lire Sheet] --> C2{Slots libres ?\nmax 4 en parallèle} C2 -->|oui| C3[POST /transfer\npour chaque slot] C3 --> C4[Marquer EN COURS\n+ job_id] C4 --> C5[MAJ Sheet] C2 -->|non| STOP([⛔ stop]) end

Chaîne A — Polling des jobs actifs

Pour chaque ligne avec statut EN COURS, interroge GET /status/{job_id}. Si le job est terminé (SUCCESS ou ERROR), met à jour le statut dans le Sheet.

Chaîne B — Consolidation du Rapport

Vérifie si tous les éléments d'un drive sont TRANSFÉRÉ. Si oui, marque le drive comme DÉJÀ TRANSFÉRÉ dans l'onglet Rapport. Si des erreurs persistent, marque ERREUR PARTIELLE.

Chaîne C — Lancement des transferts

Calcule le nombre de slots disponibles (MAX_PARALLEL = 4 − jobs EN COURS). Lance les prochains éléments EN ATTENTE jusqu'à remplir les slots. Chaque lancement appelle POST /transfer et reçoit un job_id en retour.

Point critique — fichiers vs dossiers rclone utilise rclone copyto pour les fichiers individuels (préserve le nom exact) et rclone copy pour les dossiers. Sans cette distinction, rclone interprète la destination d'un fichier comme un répertoire → erreur "is a file not a directory".

WF-C · Vérification des erreurs

Workflow de maintenance exécuté manuellement après WF-B pour corriger les faux positifs. Une erreur rclone ne signifie pas toujours que le fichier est absent de la destination.

Flux WF-C
flowchart LR T([▶ Manuel]) --> V1[Lire Transfert_Detail] V1 --> V2[Filtrer\nStatut = ERREUR] V2 --> V3[POST /check\nrclone lsf destination] V3 --> V4{exists ?} V4 -->|true| V5[TRANSFÉRÉ ✓\nfaux positif corrigé] V4 -->|false| V6[ERREUR 🔴\nvraie erreur confirmée] V5 --> V7[MAJ Sheet] V6 --> V7

La vérification est directe : /check utilise rclone lsf sur le drive destination pour chercher le fichier. Si lsf le trouve → le fichier est bien présent → faux positif. Le statut passe à TRANSFÉRÉ.


Cycle de vie d'un fichier

Diagramme d'états
stateDiagram-v2 [*] --> EN_ATTENTE : WF-A scan et insertion EN_ATTENTE --> EN_COURS : WF-B slot libre\nPOST /transfer EN_COURS --> TRANSFERE : rclone exit 0\nSUCCESS EN_COURS --> ERREUR : rclone exit ≠ 0\nERROR ERREUR --> TRANSFERE : WF-C vérifie\nexists=true dans destination ERREUR --> ERREUR : WF-C vérifie\nexists=false → vraie erreur TRANSFERE --> [*]
StatutSignificationProchaine action
EN ATTENTEScanné, en attente de slotWF-B chaîne C le lance
EN COURSJob rclone en cours d'exécutionWF-B chaîne A poll toutes les 5 min
TRANSFÉRÉCopie confirméeWF-B chaîne B consolide le drive
ERREURrclone a retourné un code ≠ 0WF-C vérifie l'existence réelle

Google Sheets — Structure des données

Onglet Rapport

Un enregistrement par Shared Drive. Vue consolidée de la progression.

ColonneDescription
Nom du driveClé de correspondance (upsert)
StatutÀ TRANSFÉRER / DÉJÀ TRANSFÉRÉ / ERREUR PARTIELLE
ID sourceID Shared Drive Compte A
ID destinationID Shared Drive Compte B (rempli par WF-0)
Date analyseDate de dernière mise à jour

Onglet Transfert_Detail

Un enregistrement par fichier ou dossier scanné. C'est la table principale de la migration.

ColonneDescription
CléIdentifiant unique NomDrive|Chemin — utilisé pour les upserts
Nom DriveNom du drive parent
CheminChemin relatif dans le drive (ex: Design/logo.png)
Typefichier ou dossier
StatutEN ATTENTE / EN COURS / TRANSFÉRÉ / ERREUR
Taille (Mo)Taille en Mo (vide pour les dossiers)
ID sourceID du Shared Drive source
ID destinationID du Shared Drive destination
DébutHorodatage de démarrage du transfert
FinHorodatage de fin
Job IDID court du job rclone_agent (ex: 9e3c6661)

rclone_agent — API Reference

Agent HTTP Python minimal hébergé sur le VPS, accessible depuis les containers Docker via http://host.docker.internal:3001. Authentification Bearer token.

Endpoints

GET /health

Vérifie l'état de l'agent et le nombre de jobs en cours.

{ "status": "ok", "total_jobs": 155, "running": 0 }

POST /transfer

Lance un transfert rclone en arrière-plan. Retourne immédiatement un job_id.

// Body
{ "src_drive_id": "0AH...", "dst_drive_id": "0AC...", "path": "Design/logo.png", "type": "fichier" }

// Response 202
{ "job_id": "9e3c6661", "log_file": "/home/sidy/scripts/logs/transfer_9e3c6661.log" }
type = "fichier" → rclone copyto Lorsque type est "fichier", l'agent utilise rclone copyto qui préserve le nom exact du fichier destination. Pour "dossier", rclone copy est utilisé (copie le contenu du dossier).

GET /status/:job_id

Interroge l'état d'un job. Retourne RUNNING, SUCCESS ou ERROR.

{ "job_id": "9e3c6661", "status": "SUCCESS", "exit_code": 0,
  "started_at": "2026-03-26T05:55:17", "finished_at": "2026-03-26T05:55:28",
  "log_tail": "..." }

POST /check

Vérifie si un fichier ou dossier existe dans le drive destination (utilisé par WF-C).

// Body
{ "dst_drive_id": "0AC...", "path": "Design/logo.png", "type": "fichier" }

// Response
{ "exists": true, "path": "Design/logo.png", "type": "fichier" }

POST /scan

Scanne un Shared Drive source et retourne la liste des éléments (via rclone lsjson profondeur 2).

// Body
{ "drive_id": "0AH...", "max_depth": 2 }

// Response
{ "items": [ { "Path": "Design/logo.png", "IsDir": false, "Size": 54321 }, ... ], "count": 42 }

Infrastructure

ServiceImage / StackURL
Reverse proxyTraefik latest:80/:443 → HTTPS auto
n8nn8nio/n8nn8n.levell.cloud
rclone_agentPython 3 systemdhost:3001
Monitoring BeszelDockerVPS metrics
Transfer Monitornginx:alpinesuivi.levell.cloud