variable tutorial script linux bash unix shell nfs

linux - tutorial - ¿Hay una buena manera de detectar un montaje NFS obsoleto



ubuntu sh variable (7)

Además de las respuestas anteriores, que se cuelgan en algunas circunstancias, este fragmento comprueba todos los montajes adecuados, mata con la señal KILL y también se prueba con CIFS:

grep -v tracefs /proc/mounts | cut -d'' '' -f2 | / while read m; do / timeout --signal=KILL 1 ls -d $m > /dev/null || echo "$m"; / done

Tengo un procedimiento que quiero iniciar solo si varias pruebas se completan correctamente.

Una de las pruebas que necesito es que todos mis montajes NFS están vivos y bien.

¿Puedo hacerlo mejor que el enfoque de fuerza bruta:

mount | sed -n "s/^.* on /(.*/) type nfs .*$//1/p" | while read mount_point ; do timeout 10 ls $mount_point >& /dev/null || echo "stale $mount_point" ; done

Aquí el timeout es una utilidad que ejecutará el comando en segundo plano y lo eliminará después de un tiempo determinado, si no se SIGCHLD un SIGCHLD antes del límite de tiempo, lo que devuelve éxito / falla de la manera obvia.

En inglés: analice la salida del mount , verifique (limitado por un tiempo de espera) cada punto de montaje NFS. Opcionalmente (no en el código anterior) rompiendo en el primer montaje obsoleto.


Escribí https://github.com/acdha/mountstatus que utiliza un enfoque similar al que UndeadKernel mencionó, que he encontrado que es el más robusto: es un demonio que analiza periódicamente todos los sistemas de archivos montados mediante el procesamiento de un proceso secundario que intenta listar el directorio de nivel superior y SIGKILL si no responde en un cierto tiempo de espera, con tanto los éxitos como los fallos registrados en syslog. Eso evita problemas con ciertas implementaciones de clientes (por ejemplo, Linux más antiguo) que nunca activan tiempos de espera para ciertas clases de errores, servidores NFS que responden parcialmente pero que no responden a llamadas reales como listdir , etc.

No los publico, pero el Makefile incluido usa fpm para construir paquetes rpm y deb con un script Upstart.


Escribir un programa en C que compruebe si hay ESTALE es una buena opción si no le importa esperar a que finalice el comando debido al sistema de archivos obsoletos. Si desea implementar una opción de "tiempo de espera", la mejor manera que he encontrado para implementarla (en un programa C) es crear un proceso secundario que intente abrir el archivo. A continuación, verifica si el proceso hijo ha terminado de leer correctamente un archivo en el sistema de archivos dentro de un período de tiempo asignado.

Aquí hay una pequeña prueba del programa C para hacer esto:

#include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <sys/wait.h> void readFile(); void waitForChild(int pid); int main(int argc, char *argv[]) { int pid; pid = fork(); if(pid == 0) { // Child process. readFile(); } else if(pid > 0) { // Parent process. waitForChild(pid); } else { // Error perror("Fork"); exit(1); } return 0; } void waitForChild(int child_pid) { int timeout = 2; // 2 seconds timeout. int status; int pid; while(timeout != 0) { pid = waitpid(child_pid, &status, WNOHANG); if(pid == 0) { // Still waiting for a child. sleep(1); timeout--; } else if(pid == -1) { // Error perror("waitpid()"); exit(1); } else { // The child exited. if(WIFEXITED(status)) { // Child was able to call exit(). if(WEXITSTATUS(status) == 0) { printf("File read successfully!/n"); return; } } printf("File NOT read successfully./n"); return; } } // The child did not finish and the timeout was hit. kill(child_pid, 9); printf("Timeout reading the file!/n"); } void readFile() { int fd; fd = open("/path/to/a/file", O_RDWR); if(fd == -1) { // Error perror("open()"); exit(1); } else { close(fd); exit(0); } }


Me tomó algo de tiempo, pero aquí está lo que encontré que funciona en Python:

import signal, os, subprocess class Alarm(Exception): pass def alarm_handler(signum, frame): raise Alarm pathToNFSMount = ''/mnt/server1/'' # or you can implement some function # to find all the mounts... signal.signal(signal.SIGALRM, alarm_handler) signal.alarm(3) # 3 seconds try: proc = subprocess.call(''stat ''+pathToNFSMount, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) stdoutdata, stderrdata = proc.communicate() signal.alarm(0) # reset the alarm except Alarm: print "Oops, taking too long!"

Observaciones:

  1. Crédito a la respuesta aquí .
  2. También podrías usar un esquema alternativo:

    os.fork() y os.stat()

comprueba si la horquilla ha terminado, si se ha agotado el tiempo, puedes matarla. Deberá trabajar con time.time() y así sucesivamente.


Otra forma, utilizando shell script. Funciona bien para mí:

#!/bin/bash # Purpose: # Detect Stale File handle and remove it # Script created: July 29, 2015 by Birgit Ducarroz # Last modification: -- # # Detect Stale file handle and write output into a variable and then into a file mounts=`df 2>&1 | grep ''Stale file handle'' |awk ''{print ""$2"" }'' > NFS_stales.txt` # Remove : ‘ and ’ characters from the output sed -r -i ''s/://'' NFS_stales.txt && sed -r -i ''s/‘//'' NFS_stales.txt && sed -r -i ''s/’//'' NFS_stales.txt # Not used: replace space by a new line # stales=`cat NFS_stales.txt && sed -r -i '':a;N;$!ba;s/ //n /g'' NFS_stales.txt` # read NFS_stales.txt output file line by line then unmount stale by stale. # IFS='''' (or IFS=) prevents leading/trailing whitespace from being trimmed. # -r prevents backslash escapes from being interpreted. # || [[ -n $line ]] prevents the last line from being ignored if it doesn''t end with a /n (since read returns a non-zero exit code when it encounters EOF). while IFS='''' read -r line || [[ -n "$line" ]]; do echo "Unmounting due to NFS Stale file handle: $line" umount -fl $line done < "NFS_stales.txt" #EOF


Podrías escribir un programa en C y verificar si hay ESTALE

#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <iso646.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> int main(){ struct stat st; int ret; ret = stat("/mnt/some_stale", &st); if(ret == -1 and errno == ESTALE){ printf("/mnt/some_stale is stale/n"); return EXIT_SUCCESS; } else { return EXIT_FAILURE; } }


Un colega mío se topó con tu guión. Esto no evita un enfoque de "fuerza bruta", pero si puedo en Bash:

while read _ _ mount _; do read -t1 < <(stat -t "$mount") || echo "$mount timeout"; done < <(mount -t nfs)

mount puede listar montajes NFS directamente. read -t (un shell incorporado) puede agotar un comando. stat -t (salida tersa) todavía cuelga como un ls *. ls produce resultados innecesarios, arriesga falsos positivos en listas de directorios enormes / lentas y requiere permisos para acceder, lo que también generaría un falso positivo si no los tiene.

while read _ _ mount _; do read -t1 < <(stat -t "$mount") || lsof -b 2>/dev/null|grep "$mount"; done < <(mount -t nfs)

Lo estamos utilizando con lsof -b (sin bloqueo, por lo que no se bloquea) para determinar la fuente de los bloqueos.

Gracias por el puntero!

  • test -d (un shell builtin) también funcionaría en lugar de stat (un estándar externo), pero read -t devuelve el éxito solo si no se agota el tiempo de espera y lee una línea de entrada. Como test -d no usa stdout, sería necesario realizar una comprobación de nivel de error (( $? > 128 )) , no vale la pena el impacto de legibilidad, OMI.