Dépannage¶
Les erreurs ci-dessous ont toutes été rencontrées pour de vrai. Pour chacune : le message exact, ce qu'il veut dire, et quoi faire.
Où lire l'erreur¶
Trois endroits, dans cet ordre :
- Le rapport de l'exécution, dans l'interface. L'étape qui a échoué est nommée, avec son message.
- Le message de la sonde, dans le même rapport. Les sondes sont écrites pour dire quoi corriger, pas seulement que quelque chose ne va pas.
- Les journaux du runner, chez vous.
docker logs restoreproof-runner. Quand une commande échoue dans un bac à sable, l'application n'en montre que le code de sortie et une ligne, suivie de(full output in the runner log): la sortie complète, qui peut contenir des données de votre sauvegarde, n'est écrite que là.
ldap_add: Undefined attribute type (17)¶
Ce que ça veut dire¶
Votre annuaire utilise un schéma personnalisé — des attributs ou des classes d'objets que vous avez ajoutés — et ce schéma n'est pas dans la sauvegarde. Le serveur du bac à sable démarre vierge : il ne connaît pas ces attributs, et refuse la première entrée qui en porte un.
Ce n'est pas un défaut du produit. C'est une vraie découverte : votre dump d'annuaire ne peut pas être rechargé sur un serveur neuf, et c'est exactement ce que vous êtes venu vérifier.
Ce que fait le runner aujourd'hui¶
Avant d'écrire la première entrée, il compare les attributs et classes utilisés par le dump au sous-schéma que l'annuaire du bac à sable déclare. S'il en manque, l'étape échoue avec la liste complète :
the dump uses attribute types [monattribut, monautreattribut] and object classes [maclasse] that the target directory does not define. They come from a custom schema that is not part of the backup…
C'est le message que vous devriez voir. Le Undefined attribute type (17) brut,
une erreur à la fois, apparaît quand ce contrôle n'a pas pu s'exécuter — un
serveur qui ne répond pas à une requête sur son root DSE. Dans ce cas, chaque
exécution ne vous apprend qu'un attribut manquant, et il en faut autant que de
schémas absents.
Quoi faire¶
Extrayez le schéma de votre serveur de production, ajoutez-le à ce que vous
sauvegardez, et rechargez-le dans le bac à sable avant l'étape
restore_ldap.
Sur OpenLDAP, l'export du schéma :
Dans le plan, une étape exec_in_sandbox entre start_sandbox et
restore_ldap :
{
"type": "exec_in_sandbox",
"name": "charger le schéma",
"config": {
"cmd": ["ldapadd", "-Y", "EXTERNAL", "-H", "ldapi:///", "-f", "/workspace/schema.ldif"]
}
}
Le chemin doit être exact
cmd est exécuté sans shell : /workspace/*/schema.ldif ne sera pas
développé. Voir l'archive imbriquée ci-dessous.
Une archive imbriquée¶
Le symptôme¶
Votre sauvegarde s'appelle backup.tar.gz et se décompresse en :
Vous avez écrit input: "data.ldif" et le plan trouve le fichier. Puis vous
ajoutez un exec_in_sandbox avec /workspace/*/schema.ldif — et il échoue avec
un « fichier introuvable » qui nomme littéralement le chemin avec l'étoile
dedans.
Ce qui se passe¶
Les deux étapes ne résolvent pas les chemins de la même façon, et c'est délibéré.
Les champs input (unpack, restore_postgres, restore_mysql,
restore_mongo, restore_ldap) descendent dans l'arborescence. Si data.ldif
n'est pas à la racine, le runner parcourt les sous-répertoires et compare le nom
de chaque fichier. Les jokers sont acceptés. Si plusieurs fichiers correspondent,
le plus gros gagne. C'est ce qui rend input: "data.ldif" correct même dans un
répertoire horodaté dont le nom change à chaque sauvegarde.
Le champ cmd de exec_in_sandbox, lui, est exécuté directement dans le
conteneur, sans shell. Il n'y a ni développement de joker, ni substitution de
variable, ni redirection. Le * est passé tel quel au programme, qui n'en fait
rien.
Quoi faire¶
Trois possibilités, de la meilleure à la moins bonne.
1. Aplatir l'archive. Si vous maîtrisez la sauvegarde, construisez-la sans le répertoire horodaté :
C'est la seule qui rend le plan stable dans le temps.
2. Appeler un shell explicitement, quand vous ne maîtrisez pas l'archive :
Cela suppose que l'image du bac à sable contient un shell — c'est presque toujours le cas, mais pas toujours.
3. Écrire le chemin en dur, si le nom du répertoire ne change pas.
Le canari échoue et vous ne lui avez rien demandé¶
Le message¶
This probe was asked to prove nothing, so it proves nothing. Walking the restored tree found 1 842 file(s) in 96 directories, 412 998 231 bytes in total, but no check was configured…
Ce que ça veut dire¶
Ce n'est pas une panne. C'est l'étape de réglage.
La sonde filesystem-canary a bien parcouru vos données restaurées. Elle refuse
seulement de rendre un PASS alors qu'on ne lui a rien demandé de vérifier :
compter des fichiers ne prouve pas qu'une sauvegarde est restaurable, et un
PASS qui n'a rien vérifié est une preuve qui ment.
Cette sonde passait autrefois sur un unique fichier vide, et l'exécution était signée comme une preuve. Plus maintenant.
Quoi faire¶
Le message vous rend les trois chiffres de votre arborescence. Reportez-les :
| Ce que vous avez lu | Où le mettre |
|---|---|
1 842 file(s) |
RESTOREPROOF_CANARY_MIN_FILES — prenez un peu en dessous, par exemple 1700. |
412 998 231 bytes |
RESTOREPROOF_CANARY_MIN_TOTAL_SIZE — par exemple 400000000. |
Ces deux seuils attrapent la sauvegarde qui rétrécit silencieusement de plusieurs milliers de fichiers à une poignée.
Ajoutez au moins un fichier nommé, parce qu'un volume global ne dit rien de ce qu'il contient :
| Variable | Ce qu'elle ajoute |
|---|---|
RESTOREPROOF_CANARY_PATH |
Forme ancienne de RESTOREPROOF_CANARY_FILES, toujours lue : un ou plusieurs chemins qui doivent exister. |
RESTOREPROOF_CANARY_FILES |
Les mêmes, plus ce qu'ils doivent contenir, peser ou valoir en SHA-256. |
RESTOREPROOF_CANARY_PATTERN |
Un motif qu'au moins un fichier doit satisfaire. |
Un fichier vide au bon nom se restaure aussi bien que le vrai. Seul
RESTOREPROOF_CANARY_FILES, en écriture JSON, permet d'exiger un contenu :
L'image d'une sonde ne se télécharge pas¶
Le message¶
failed to pull image ghcr.io/kolapsis/restoreproof/probe-postgres:latest
Ce que ça veut dire¶
Le runner n'a pas pu récupérer le conteneur de la sonde. Les images sont sur
ghcr.io, elles sont publiques, et le runner les tire à la demande.
Quoi faire¶
Vérifiez que le runner peut sortir vers ghcr.io. Depuis la machine du
runner :
Si cette commande échoue, c'est un problème de réseau ou de proxy, pas de RestoreProof.
Si votre réseau est fermé, utilisez votre propre miroir. Le runner construit
le nom de l'image comme <préfixe><type>:<étiquette> ; l'étiquette est par
défaut la version du runner lui-même, et les deux morceaux se règlent :
Miroitez alors les dix images : probe-archive-integrity,
probe-filesystem-canary, probe-certificate, probe-postgres, probe-mysql,
probe-mongodb, probe-sqlite, probe-pocketbase, probe-ldap, probe-http.
Vérifiez que Docker répond sur la machine du runner :
Le conteneur du runner tourne en root et atteint le socket monté : si
docker info répond sur l'hôte, il répond aussi dans le conteneur.
Le runner n'apparaît pas « en ligne »¶
Comment l'état est décidé¶
Le runner ouvre un canal vers le Control Plane et le garde ouvert. Il y envoie
un battement de cœur toutes les 30 secondes. Un runner silencieux pendant
90 secondes — trois battements manqués — passe à offline. Un canal fermé le
dit immédiatement.
Quoi vérifier, dans l'ordre¶
1. Le runner tourne-t-il ?
Cherchez control channel established. Sans cette ligne, il n'est pas connecté,
et un runner sans canal ne reçoit jamais de travail.
2. L'adresse est-elle la bonne ?
Le canal du runner est en gRPC, sur son propre port. Ce n'est pas l'URL de l'API ni celle de l'application :
Une valeur en localhost dans un déploiement réel ne joindra rien.
3. La clé d'API est-elle la bonne ?
Elle commence par rp_. Elle est propre à une organisation. Une clé refusée
produit Unauthenticated dans les journaux du runner — un message différent de
celui d'un serveur injoignable, qui produit une erreur de connexion suivie d'un
délai de reconnexion qui s'allonge.
Si vous avez régénéré la clé dans l'interface, l'ancienne ne vaut plus rien : remettez la nouvelle dans la configuration du runner et redémarrez-le.
4. Le réseau sortant est-il ouvert ?
Le runner n'a besoin d'aucun port entrant. Il lui faut seulement pouvoir sortir
en HTTPS/gRPC vers le Control Plane, et vers ghcr.io pour les images.
5. La vérification TLS.
RESTOREPROOF_TLS_SKIP=true ne doit jamais être utilisé en production. Si c'est
la seule façon de faire fonctionner le runner, c'est votre chaîne de certificats
qu'il faut corriger, pas cette variable.
Le runner refuse un téléchargement ou une source locale¶
Le runner ne télécharge que depuis les hôtes listés dans
RESTOREPROOF_FETCH_HOSTS et ne lit que les dossiers listés dans
RESTOREPROOF_LOCAL_ROOTS (voir ce que le runner a le droit
d'atteindre).
Le message de l'étape fetch dit toujours quelle entrée ajouter. Après la
modification, redémarrez le runner.
the runner does not download from <hôte>: add "<hôte>" to RESTOREPROOF_FETCH_HOSTS¶
L'hôte de la source, ou celui vers lequel elle redirige, n'est pas dans la
liste. Ajoutez l'entrée que le message donne à RESTOREPROOF_FETCH_HOSTS, en
la séparant des autres par une virgule. Le message voisin the runner downloads
from no host while RESTOREPROOF_FETCH_HOSTS … is empty dit la même chose
pour un runner dont la liste est encore vide : c'est le cas d'un runner
déployé avant que vous ayez créé vos sources.
the runner never connects to 169.254.169.254¶
L'adresse demandée, ou celle vers laquelle le nom se résout, est une adresse locale au lien ou l'adresse de métadonnées d'un cloud. Elle reste refusée même listée : c'est par elle qu'une machine virtuelle obtient ses identifiants. Une sauvegarde ne s'y trouve jamais ; vérifiez l'URL de la source.
the runner does not connect to the loopback address 127.0.0.1¶
La source vise la machine du runner elle-même, ou un nom qui se résout vers
elle. Si c'est voulu, par exemple pour un MinIO installé sur la même machine,
ajoutez à RESTOREPROOF_FETCH_HOSTS l'entrée que le message propose,
localhost:9000 pour ce MinIO ; un nom d'hôte ordinaire ou un *.domaine ne
l'autorisent pas.
source path "…" is refused: it is outside the directories listed in RESTOREPROOF_LOCAL_ROOTS¶
Le chemin de la source locale n'est dans aucun des dossiers autorisés. Ajoutez
le dossier que le message propose, ou un dossier parent, à
RESTOREPROOF_LOCAL_ROOTS. Si le message dit plutôt a symbolic link takes it
out of the directories listed, le chemin est bien dans un dossier autorisé
mais un lien symbolique l'en fait sortir : pointez la source vers
l'emplacement réel du fichier, ou ajoutez cet emplacement à la liste.
RESTOREPROOF_LOCAL_ROOTS (fetch.local_roots in config.yaml): … overlaps …¶
Le runner refuse de démarrer : un des dossiers listés contient son propre
dossier de travail, son dossier de secrets ou son fichier de configuration, ou
se trouve à l'intérieur de l'un d'eux. / ou /etc provoquent ce refus.
Listez les dossiers qui contiennent les sauvegardes, et rien de plus large.
Autres messages fréquents¶
The run exceeded its timeout of … (timeout_seconds of the plan)¶
L'exécution a duré plus longtemps que le délai d'expiration du plan, une heure par défaut. Le runner a tout arrêté et détruit les conteneurs. Si la restauration est simplement longue, augmentez le délai dans le plan. Si elle ne l'est pas d'habitude, les journaux du runner montrent l'étape sur laquelle elle s'est arrêtée.
… is larger than the runner allows (fetch.max_bytes in config.yaml)¶
Le fichier téléchargé, ou ce qu'une étape unpack en tire, dépasse la limite
du runner, 512 Gio par défaut. Le fichier partiel a été supprimé. Si la
sauvegarde est vraiment aussi grosse, relevez RESTOREPROOF_FETCH_MAX_BYTES
(par exemple 1t) ; sinon, l'archive est anormale, et c'est justement ce
que la limite arrête.
probe "…" is refused: … is not an official RestoreProof probe image¶
Une sonde personnalisée nomme une image qui n'est pas une image officielle de
RestoreProof. Si l'image est bien la vôtre, ajoutez l'entrée que le message
donne à RESTOREPROOF_PROBE_IMAGES, ou un préfixe terminé par *. Voir
Sondes — L'image.
environment variable RESTOREPROOF_… is refused¶
Une référence env:// vise une variable du runner lui-même. Ces variables ne
sont jamais lues par un plan ; donnez à votre secret un nom qui ne commence pas
par RESTOREPROOF_, et vérifiez aussi l'env_prefix de la configuration.
api error NoSuchKey: The specified key does not exist¶
Ce message apparaît pendant l'étape fetch, au moment du ListObjectsV2. Le
point d'accès saisi est celui du bucket, recopié depuis la console du
fournisseur : https://mon-bucket.s3.fr-par.scw.cloud. Le nom du bucket y est
déjà, et le runner le rajoute derrière, si bien que le fournisseur cherche un
objet nommé mon-bucket/.
Renseignez le point d'accès régional, sans le nom du bucket :
https://s3.fr-par.scw.cloud. Le runner corrige désormais cette adresse
lui-même et l'écrit dans son journal sous la forme s3 endpoint normalized.
Le message voisin NoSuchBucket est autre chose : le nom du bucket est faux, ou
le bucket existe dans une autre région que celle configurée.
no sandbox container running - start_sandbox step must precede restore step¶
Une étape restore_* est placée avant tout start_sandbox. exec_in_sandbox
rend le même message, en se nommant à la fin. Ces deux familles d'étapes
travaillent dans le dernier conteneur démarré ;
sans conteneur, elles n'ont rien à faire. Remettez les étapes dans l'ordre.
nothing matching "dump.sql" in the workspace, at its root or below¶
Le fichier n'est nulle part dans l'espace de travail, ni à la racine ni dans les sous-répertoires. Les causes habituelles :
- l'étape
unpackmanque, et le dump est encore dans l'archive ; - le nom n'est pas celui que vous croyez — essayez un motif,
input: "*.sql"; - le
fetcha bien récupéré autre chose que ce que vous pensiez.
cannot auto-detect archive format from filename¶
L'étape unpack déduit le format de l'extension, et le nom de votre fichier ne
finit par aucune de celles qu'elle connaît (.tar, .tar.gz, .tgz,
.tar.bz2, .tbz2, .tar.xz, .txz, .gz, .zip). Donnez le format
explicitement dans l'étape.
No archive found to validate: nothing here proves the backup is readable¶
La sonde archive-integrity n'a trouvé aucune archive. C'est presque toujours
parce que le plan contient une étape unpack : l'archive a été décompressée et a
disparu. Cette sonde ne sert que dans un plan qui ne décompresse pas. Si
vous décompressez, la vérification du contenu revient à
filesystem-canary.
backup is 97h12m0s old, older than the 26h allowed by max_age¶
Le fichier se restaure très bien. Il est seulement vieux : la tâche qui écrit la
sauvegarde s'est arrêtée sans que personne ne le remarque. C'est la seule chose
qu'un test de restauration ne peut pas déduire des données elles-mêmes, et c'est
pour cela que max_age existe.
Le message donne la date d'écriture à la source.
the directory server truncated the search results before returning every entry¶
La sonde ldap compte les entrées page par page, 500 à la fois, précisément pour
dépasser la limite par défaut de slapd. Ce message signifie que le serveur a
quand même coupé la réponse.
Ce n'est pas un annuaire incomplet : c'est une limite du serveur du bac à
sable, sans rapport avec votre sauvegarde. Relevez la sizelimit du serveur dans
la configuration du bac à sable.
An assertion is configured but no table or query provides a value to check¶
Vous avez donné un seuil, mais rien à compter. Renseignez la table ou la requête
de la sonde concernée — par exemple RESTOREPROOF_PG_TABLE ou
RESTOREPROOF_PG_QUERY.
La sonde échoue plutôt que de passer : une assertion qui ne peut pas être évaluée n'est pas une assertion satisfaite.
secret_refs.access_key: must be a reference, never the secret itself¶
L'enregistrement d'une source est refusé par un 400. La valeur envoyée n'a pas
la forme d'une référence. Elle doit s'écrire env://NOM_DE_VARIABLE,
file://nom_de_fichier ou static://cle. Le message nomme le champ, jamais la
valeur : rien de ce que vous avez tapé n'apparaît dans le journal.
Plusieurs variantes du même refus :
a local source takes no secret reference— un disque local ou un partage NFS ne porte pas d'identifiant : ce type de source ne prend aucune clé danssecret_refs.unknown secret reference for a http source, allowed keys: authorization— une source HTTP n'accepte quesecret_refs.authorization, que le runner transforme en en-têteAuthorization. Un autre en-tête se met dans l'étapefetchdu plan, sousheaders, avec une valeursecret://….put credentials in secret_refs as a reference— un champpassword,token,secret,authorization,access_keyousecret_keys'est glissé dansconfig. Ces clés y sont refusées.
vault:// et sops:// sont refusés aussi : ils ne sont pas encore pris en
charge.
secret … not found: it is neither an env:// reference, nor a file:// reference, nor a static:// reference¶
Cette fois c'est le runner, à l'exécution. La référence est bien écrite mais ne
se résout pas chez lui : la variable d'environnement est vide ou absente, le
fichier est illisible, ou la clé ne figure pas dans sa table static:.
Le message nomme la clé en cause. Vérifiez la configuration du runner et son environnement, pas le plan.
Vous n'avez pas besoin d'attendre une exécution pour le savoir : la page du runner liste les références manquantes, dès le battement suivant. Voir Fournir les secrets au runner.
402 Payment Required¶
Ce n'est pas une erreur technique. Vous avez atteint une limite de votre offre : nombre de plans, nombre de sources, nombre de runners, ou nombre d'exécutions sur le mois. La réponse dit laquelle.
Ce qu'il faut rassembler avant de nous écrire¶
- L'identifiant de l'exécution qui a échoué.
- Le message exact de l'étape ou de la sonde.
- Les journaux du runner autour de l'horodatage.
- Le plan, sans les valeurs de secrets — les références telles qu'elles sont
écrites (
secret://env://MA_VAR,secret://file://ma_cle,secret://static://ma_cle) sont utiles, la valeur qu'elles désignent ne l'est pas.