Tristan est déjà intervenu sur le blog fin 2021. Le voici de retour avec cet article qui explique comment résoudre le problème d’un Raspberry Pi qui ne boote plus à cause de la défaillance d’un disque dur qui lui est relié. Je laisse volontiers la parole à Tristan (@BlindVador)
Au sommaire :
Éviter le blocage de votre Raspberry Pi en cas de défaillance d’un disque externe
Salut a toutes et tous!
Je reviens vers vous avec un petit bout de code tout bête en python, mais qui fait bien des miracles!
J’ai à la maison un NAS fait avec un Raspberry Pi et Samba, mon Pi me sert en temps normal a faire tourner octoPrint, mais le temps ou je ne m’en sert pas il fait aussi d’autres trucs, entre autre Samba.
Hors il y a peu j’ai eu une défaillance sur mon hub USB qui me permet d’alimenter les deux disques durs que j’emploie dans ma configuration.
Mon Pi s’est alors mis a tenter de booter en boucle sans y parvenir, finissant par s’éteindre, j’ai du retélécharger une distro linux (que je n’avais plus sous le coude…) flasher une carte SSD vide, éteindre le Pi, mettre la carte sSD dans le Pi, mettre ma carte habituelle dans le convertisseur SD vers USB, allumer le Pi, me connecter, brancher, tout ça pour aller commenter trois lignes dans /etc/fstab.
Je me suis dit qu’a l’avenir je voulais un système qui soit moins méchant avec ma pauvre framboise, j’aime pas la voir toute paniquée comme ça… alors il me faut un script qui tienne compte des conditions réelles, si un disque est défaillant ou si quelque chose ne va pas, soit on gère le problème soit on me demande de le gérer.
Pour rappel a ceux qui ne me connaissent pas, je suis totalement aveugle, faute de place sur mon Pi je n’ai pas le loisir d’y installer des logiciels de lecture d’écran, pour ne pas dégrader les performances, je n’ai aucun clavier de libre, je n’ai même pas un écran dans tout mon foutu labo pour brancher le Pi et demander a quelqu’un de regarder quand ça déconne, il faut que je me débrouille en SSH.
Donc moins je perds la connexion avec le Pi, mieux c’est. Voilà donc le script du jour.
Prérequis:
Comme dit je n’ai aucun écran, et se script doit de toute manière être exécuté par la crontab root, donc ne rien afficher a l’écran, pour changer un peu de nos habitudes, on va miser sur une sortie vocale via un TTS.
Si vous voulez que le rendu soit plus visuel, je vous invite a adapter le script a votre convenance. Pour ceux qui sont aventuriers, vous aurez besoin de:
espeak installé sur le Pi.
sudo apt-get install espeak
les voix de chez mbrola pour rendre ça un peu moins gerbant.
un périphérique audio branché et fonctionnel sur le Pi.
Un excellent article de François vous expliquera super bien comment faire parler votre Raspberry Pi, et ça vous sera souvent utile si à l’avenir vous lisez et utilisez mes script.
Nous aurons besoin de Python installé sur la machine également, (j’ai essayé de faire le script en bash mais ça m’a soulé, alors c’est du Python et c’est tout… 😀 )
Avant de débuter, se script est fait pour être adaptable facilement, il est lourdement commenté, je préfère toujours en dire trop que pas assez, et pas juste balancer un bout de code comme ça et débrouillez vous avec ça.
Le script fonctionne selon un concept rudimentaire, on va tout simplement monter le disque, si le disque se monte bien, on le verra en récupérant la liste des éléments prévus au point de montage.
Un dossier clean pour recevoir le montage du disque, ou il n’y a rien d’autre, histoire que lorsque votre disque est monté, le dossier soit rempli avec des données contenus sur le disque, si évidemment il y a d’autres trucs dans votre dossier point de montage, le script les détectera et croira que le disque est présent alors que non.
Un article du blog explique là encore très bien comment créer son NAS avec Samba et Raspberry Pi, je vous invite a le consulter.
Un fichier a la racine de chaque disque appelé nd<nombre>.txt (notez que le nombre en question doit être unique a chaque disque comme 1/2/3… c’est en fait ce qui permet de déterminer quel disque était identifié comme /dev/sda1, sda2, car lors de l’utilisation de plusieurs disques après un redémarrage il peut arriver que l’ordre des disque soit inversé et donc si le fichier de configuration de samba ne reflète pas cette modification que toute votre installation soit aux fraises),
Le script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
<span style="font-family: courier new, courier, monospace;"># -- coding: utf-8 -- #on commence par importer le module os qui va nous permettre de #faire d'une pierre deux coups, passer des commandes bash au pi et aussi #lister les fichiers présents aux points de montage. import os #On prépare une variable qu'on appellera confirmed avec une valeur de 0 #a chaque fois qu'on confirmera qu'un disque est monté, on incrémentera sa valeur pour dire combiens de disque sont #présent sur le système actuellement; confirmed=0 #La variable suivante détermine les paramètres de la voix que nous allons utilisé pour faire parler notre pi #libre a chacun de les ajuster, changer la langue, (il faudra réécrire les messages) #débit, hauteur... autant de paramètres qu'on peu avoir envie de modifier en une seul fois au lieu de parcourir tout le script. #consultez l'aide de espeak pour trouver les différents paramètres utilisable. #veuillez noter que a la fin entre le dernier paramètre et le guillemet il y a un espace #ceci pour éviter toute anomalie lors de l'interprétation de la commande, veuillez conservé un espace entre #le paramètre et le guillemet. speaking_cmd="espeak -v mb/mb-fr1 -s 140 " #décriptons un peu la ligne suivante. #os.system() on fait appelle a la méthode system du module os. #system atant de nous comme paramètre une chaine de caractère représentant une commande a envoyer a l'interpréteur. #juste après la ( on trouve speaking_cmd+"\" #cette syntaxe un peu déconcertante viens du fait que on passe en paramètre une chaine de caractère qui est en fait le résultat de la concaténation de deux chaines #speaking_cmd qui contiens les paramètres et la commande espeak, + l’opérateur de concaténation, #" qui marque l'entré dans la nouvelle chaine de caractère comprenant elle le message envoyé a espeak. #vous noterez que la chaine commence par: \" et se termine comme ça aussi. #tout simplement parce que pour éviter toute incohérence lors du traitement de la commande espeak, il est préférable d'encadrer son texte avec des guillemets. #hors, quelqu'un d'autre ici interprète les guillemets... python, pour éviter que python crois que les guillemets de la chaine de caractère sont pour lui et les traite, on les échappe; os.system(speaking_cmd+"\"Vérification de la présence des disque pour le système nas.\"") #on commence par monter un disque. adaptez le script selon combien vous en avez. #on retrouve os.system, la chaine de caractère mount... qui représente la ligne de commande pour monter un disque sur un point de notre arborescence. #adaptez le chemin de celle-ci selon votre propre besoin. os.system("mount /dev/sda1 /media/nas/nd1") #ici on va tester une condition très simple pour vérifier si le disque qu'on viens de monté a bien été trouvé. #on utilise la méthode listdir de os en lui passant en paramètre un chemin vers le point de montage pour remonter la liste des fichiers présent dans le dossier. #mais avant tout on récupère la longueur de cette dite liste, c'est pour cela qu'on obtiens len(listdir(chemin)) #ou traduit en bon français longueur de la liste(liste du contenu de(chemin vers le point de montage)) #on obtiens donc en sortie un integer qu'on va tester de se pas pour vérifier s'il est égal a 0. #si c'est 0, alors la liste est vide, et de fait il n'y a rien dans le dossier indiqué comme point de montage #deux cas de figure alors, soit votre disque n'est pas monté, soit votre disque est vide. C'est une des limites de se système on présupose que le disque n'est pas vide. #pour détecter qu'il est bien là. Je n'ai pas trouvé après mes recherches d'autres métodes pour détecter et confirmer la présence d'un disque if(len(os.listdir("/media/nas/nd1"))==0): disca_status="Oups! le disque de sauvegarde semble être déconnecté... veuillez vérifier votre installation, puis réessayer. " else: #si le disque a bien été détecté comme étant en ligne, alors on incrémente confirmed qui passe de 0 à 1, #ceci pouvant par exemple permettre d'adapter le message a la fin du script pour savoir combien de disque tourne actuellement. #notez que je nomme explicitement les disque, parce que c'est la fonction que je leur ai donné. #adaptez ça a votre propre installation. confirmed=confirmed+1 disca_status="Disque de sauvegarde en ligne et paré! " #on reprend comme tout a l'heure, référez vous au commentaires explicatif précédent le bloque d'instruction similaire. #vous pouvez copier ses bloques selon combien de disque vous avez chez vous. os.system("mount /dev/sdb1 /media/nas/nd2") if(len(os.listdir("/media/nas/nd2"))==0): discb_status="aille! le disque principale de stocage semble être déconnecté. Veuillez vérifier votre installation, puis essayer a nouveau ." else: discb_status="Le disque principale de stockage fonctionne selon des paramètres nominaux." confirmed=confirmed+1 #on teste si aumoins un disque a bien été monté. if(confirmed>0): #lors d'un redémarrage du NAS il peut arriver que le disque 1 se monte avant le disque 2. #Ceci est due au fait que lorsqu'on branche le disque il n'a pas de nommage stable. #si par exemple le disque habituellement prévue en dev/sda se retrouve en /dev/sdb et le sdb en sda #alors nos configurations samba serons a la ramasse et lorsqu'on tentera d'ouvrir par exemple /nas/disck1/storage depuis une machine distante, on obtiendra une erreurs réseau... puisque le chemin pointe vers un emplacement qui n'existe pas. #Pour palier a se problème je n'ai pas trouvé de meilleur solution que d'enregistrer a la racine de chaque disque un fichier vide appelé avec le nom du disque #ou en tout cas celui que par convention je voudrais qu'il ai. #il me suffit alors après le montage faire un simple test pour voir quel disque c'est monté et où. #une fois que je sais quel disque est sur quel point de montage, je remplacerai le fichier de configuration de samba smb.conf #par une version tenant compte de l'ordre de montage. #NB: dans mon dossier de session, j'ai un dossier bin contenant quelques script python et leurs fichiers liés. #adaptez selon votre configuration et vos besoins. #pour rédiger votre fichier de configuration smb.conf référez vous à l’article de François sur comment créer un NAS avec un Raspberry Pi et Samba #on commence par supprimer le fichier de configuration smb #puisqu'on ne saient pas a se stade si il est correctement rédigé os.system("sudo rm /etc/samba/smb.conf") #on test voir si le disque 1 c'est monté à l'emplacement 1 if(os.path.isfile("/media/nas/nd1/nd1.txt")): #alors on fait une copie du fichier smb.conf tenant compte de cette configuration #on le prend dans son point de stockage (ou je conserve les deux version du fichier) #et on le renomme a la volé avec le nom que samba atant smb;conf os.system("sudo cp /home/pilot/bin/nasbooter/smbv1.conf /etc/samba/smb.conf") #on préparent un simple message m'indiquant lors du démarrage du NAS comment samba est configuré. #bien entendu vous pouvez adapter le texte comme vous voulez, dans mon cas comme j'ai deux possibilités, et une mauvaise mémoire des chiffres je voulais le faire avec des lettres #mais "a" ou "b" prononcé à l'orale par une voix synthétique dans un environnement bruyant peuvent être mal-entendu. #c'est pourquoi j'ai opté pour l'alphabet radio, ce qui nous donne alfa ou bravo. conftype=" Samba en configuration alfa. " #si le bloque 1 ne c'était pas exécuté, cela signifie que #les disques se sont inversé. #on fait donc le même traitement que précédemment, en tenant compte de cette possibilité. if(os.path.isfile("/media/nas/nd1/nd2.txt")): os.system("sudo cp /home/pilot/bin/nasbooter/smbv2.conf /etc/samba/smb.conf") conftype=" Samba en configuration bravo. " #Comme on a commencé par supprimer la configuration de samba, on test juste qu'une des deux configuration est bien appliqué. #si le dossier /etc/samba contiens au moins 1 fichier de configuration alors on peu démarrer le serveur. if(os.path.isfile("/etc/samba/smb.conf")): os.system("samba start") #on en profite pour faire dire a espeak un petit message qui récap combien de disque sont en ligne et ce qu'il se passe. #Vous noterez cette fois que j'utilise str(confirmed) qui permet de convertir a la voler #confirmed qui est un entier et donc pas concaténable avec une chaine #en une chaine qui elle peut être utilisée. os.system(speaking_cmd+"\""+str(confirmed)+"disques trouvé. "+disca_status+" "+discb_status+" Démarrage"+conftype+" terminé.\"") #instant je ne dois pas me perdre dans les indentations... #ici se premier sinon correspond a sinon, si aucun fichier de configuration samba n'a été trouvé. else: os.system(speaking_cmd+"\"Erreur lors de la configuration de samba. Aucun fichier de configuration appliqué. Veuillez vérifier votre installation, et réessayer.\"") #on a finit avec se niveau d'indentation. #nous clôturons donc le script en tenant compte d'une dernière possibilité, #aucun de nos disque n'a été trouvé connecté au nas, et donc nous n'avons rien fait du tout. else: os.system(speaking_cmd+"\"Aucun disque trouvé en ligne. Serveur nas en attente, veuillez vérifier votre installation, puis réessayer.\"")</span> |
Le script sans les commentaires
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# -- coding: utf-8 -- import os confirmed=0 speaking_cmd="espeak -v mb/mb-fr1 -s 140 " os.system(speaking_cmd+"\"Vérification de la présence des disque pour le système nas.\"") os.system("mount /dev/sda1 /media/nas/nd1") if(len(os.listdir("/media/nas/nd1"))==0): disca_status="Oups! le disque de sauvegarde semble être déconnecté... veuillez vérifier votre installation, puis réessayer. " else: confirmed=confirmed+1 disca_status="Disque de sauvegarde en ligne et paré! " os.system("mount /dev/sdb1 /media/nas/nd2") if(len(os.listdir("/media/nas/nd2"))==0): discb_status="aie! le disque principal de stockage semble être déconnecté. Veuillez vérifier votre installation, puis essayer a nouveau ." else: discb_status="Le disque principale de stockage fonctionne selon des paramètres nominaux." confirmed=confirmed+1 if(confirmed>0): os.system("sudo rm /etc/samba/smb.conf") if(os.path.isfile("/media/nas/nd1/nd1.txt")): os.system("sudo cp /home/pilot/bin/nasbooter/smbv1.conf /etc/samba/smb.conf") if(os.path.isfile("/media/nas/nd1/nd2.txt")): os.system("sudo cp /home/pilot/bin/nasbooter/smbv2.conf /etc/samba/smb.conf") conftype=" Samba en configuration bravo. " if(os.path.isfile("/etc/samba/smb.conf")): os.system("samba start") os.system(speaking_cmd+"\""+str(confirmed)+"disques trouvé. "+disca_status+" "+discb_status+" Démarrage"+conftype+" terminé.\"") else: os.system(speaking_cmd+"\"Erreur lors de la configuration de samba. Aucun fichier de configuration appliqué. Veuillez vérifier votre installation, et réessayer.\"") else: os.system(speaking_cmd+"\"Aucun disque trouvé en ligne. Serveur nas en attente, veuillez vérifier votre installation, puis réessayer.\"") |
Pour télécharger le script au format zip cliquez sur ce lien
Installer le script
pour que le script soit exécuté au démarrage du raspberry, il faut éditer la crontab de l’utilisateur root. Pour ce faire, entrer:
sudo crontab -e
puis ajouter la ligne:
@reboot python /chemin/vers/le/fichier.py
faire ctrl x puis y et Entrée pour sauvegarder et rebooter le Raspberry Pi pour tester.
N’oubliez surtout pas le sudo avant crontab, sinon vous éditerez la crontab avec les privilèges standards et votre script nécessitant plusieurs autorisations superuser ne pourra pas s’exécuter normalement.
Ping : Éviter le blocage de votre Raspberry Pi en cas de défaillance d’un disque externe – Jhc Info
Merci Tristan
Super idée et facile à mettre en place
Hello.
Je reviens ici pour dire que j’ai découvert une faiblaisse sur se script.
j’ai pas eu des masses de temps pour m’en occuper, mais c’est un problème qu’il va me faloir corriger.
En gros, régulièrement mon raspberry intervertie le disque 1 et le disque 2, alors dans se cas le nas fonctionne parfaitement mais du coup windows ne peu plus y accèder, c’est énervant parce que entre autre certaines machines ici on des racourcis qui pointe vers des dossier du nas pour simplifier l’accet a des documents partagés.
Ce que je pense faire, c’est créer ma uellement sur le disque un fichier sans extention, dont le nom sera genre nd1. ou nd2.
python recherchera la présence d’un des deux fichiers sur le disque et modifiera /etc/samba/smb.conf fonction de ce qu’il a trouvé…
si quelqu’un vois une solussion pour fixer les disque sans intervertir leur point de montage ou sans risquer de bloquer le nas au démarage… je serais ravie… :d
Merci encore a tous pour la lecture.
Ping : Éviter le blocage de votre Raspberry Pi en cas de défaillance d’un disque externe