2011-01-10 8 views
6

Hola a todos, Linux tiene muchas funciones geniales en procfs y sysfs, y herramientas como vmstat amplían bastante, pero tengo la necesidad de recopilar datos de una variedad de estos sistemas y esperaba aprovechar una utilidad unificada de Python en lugar de hackear juntos un conjunto de scripts dispares.¿Hay un módulo de python para analizar el sysfs de Linux?

Para poder hacer eso, primero necesito identificar si Python tiene o no los pedazos que necesito para analizar/procesar adecuadamente los diferentes puntos de recolección de datos. Entonces, la esencia de mi pregunta:

¿Hay un módulo python que maneja/analiza los objetos sysfs ya?

He buscado una bestia a través de Google, Usenet y varios foros, pero todavía no he encontrado nada inteligente o funcional. Entonces, antes de grabar una, pensé en verificar aquí primero.

+0

Bump !!! Hay [algo] (https://github.com/ponycloud/python-sysfs) basado en esta pregunta –

Respuesta

1

No estoy seguro de por qué necesita algo específico, en su mayoría son archivos de texto, simplemente puede meterse con ellos directamente.
No hay ningún módulo de Python que lo haga hasta donde yo sé.

+2

duh? el objetivo de un módulo de este tipo sería acomodar la lectura de los archivos de una manera estructurada ... es decir, sysfs.thermal_zone0.temp –

2

Prueba con esto:

from os import listdir 
from os.path import isdir, isfile, islink, join, realpath, normpath 
from keyword import iskeyword 

_norm = lambda name: name + ('_' if iskeyword(name) else '') 

def _denorm(name): 
    if name.endswith('_') and iskeyword(name[:-1]): 
     return name[:-1] 
    else: 
     return name 

def _norm_path(path): 
    return normpath(realpath(path)) 

class SysFsObject(object): 
    __slots__ = ['_path', '__dict__'] 

    @staticmethod 
    def __id_args__(path='/sys'): 
     return _norm_path(path) 

    def __init__(self, path='/sys'): 
     self._path = _norm_path(path) 
     if not self._path.startswith('/sys'): 
      raise RuntimeError("Using this on non-sysfs files is dangerous!") 
     self.__dict__.update(dict.fromkeys(_norm(i) for i in listdir(self._path))) 

    def __repr__(self): 
     return "<SysFsObject %s>" % self._path 

    def __setattr__(self, name, val): 
     if name.startswith('_'): 
      return object.__setattr__(self, name, val) 

     name = _denorm(name) 

     p = realpath(join(self._path, name)) 
     if isfile(p): 
      file(p, 'w').write(str(val)) 
     else: 
      raise RuntimeError 

    def __getattribute__(self, name): 
     if name.startswith('_'): 
      return object.__getattribute__(self, name) 

     name = _denorm(name) 

     p = realpath(join(self._path, name)) 
     if isfile(p): 
      data = open(p, 'r').read()[:-1] 
      try: 
       return int(data) 
      except ValueError: 
       return data 
     elif isdir(p): 
      return SysFsObject(p) 

No es pulido de cualquier manera, pero IIRC funciona :)

+0

¿Cómo se usa esto? ¿Es algo como lo siguiente para averiguar, por ejemplo, el nodo numa?
sysfs SysFsObject de impresión sysfs.devices.0000: 80: 00.0.numa_node –

+0

(disculpas por el pitón sin formato, la falta de nuevas líneas incrustadas en los comentarios hace que sea imposible escribir código Python en un comentario) –

+0

Por cosas como que Tendría que usar getattr: getattr (sysfs.devices, "0000: 80: 00.0"). numa_node. Python no lo permite. y: ni comenzando con números en identificadores. – filmor

2

De la respuesta de filmor, pero con el casting int() eliminado:

from os import listdir 
from os.path import isdir, isfile, islink, join, realpath, normpath 
from keyword import iskeyword 

_norm = lambda name: name + ('_' if iskeyword(name) else '') 

def _denorm(name): 
    if name.endswith('_') and iskeyword(name[:-1]): 
     return name[:-1] 
    else: 
     return name 

def _norm_path(path): 
    return normpath(realpath(path)) 

class SysFsObject(object): 
    __slots__ = ['_path', '__dict__'] 

    @staticmethod 
    def __id_args__(path='/sys'): 
     return _norm_path(path) 

    def __init__(self, path='/sys'): 
     self._path = _norm_path(path) 
     if not self._path.startswith('/sys'): 
      raise RuntimeError("Using this on non-sysfs files is dangerous!") 
     self.__dict__.update(dict.fromkeys(_norm(i) for i in listdir(self._path))) 

    def __repr__(self): 
     return "<SysFsObject %s>" % self._path 

    def __setattr__(self, name, val): 
     if name.startswith('_'): 
      return object.__setattr__(self, name, val) 

     name = _denorm(name) 

     p = realpath(join(self._path, name)) 
     if isfile(p): 
      file(p, 'w').write(val) 
     else: 
      raise RuntimeError 

    def __getattribute__(self, name): 
     if name.startswith('_'): 
      return object.__getattribute__(self, name) 

     name = _denorm(name) 

     p = realpath(join(self._path, name)) 
     if isfile(p): 
      return open(p, 'r').read()[:-1] 
     elif isdir(p): 
      return SysFsObject(p) 

Lanzar arbitrariamente a int es inesperado e incluso peligroso. Por ejemplo, si tuviera que usar ese código en cualquiera de los archivos cpulist que prevalecen en sysfs, siempre se devolverá una cadena como "0-7" en los sistemas multiprocesador. Entonces, algún día, alguien usará su código en un sistema de un solo núcleo y leerá exactamente el mismo archivo sysfs que ahora contiene "0" y devuelve un int.

En otras palabras, cualquier función que llame a ese código y espere recibir el tipo de datos nativo de sysfs (cadenas) debe emitir explícitamente a str().

+1

FYI: [' python-sysfs'] (https://github.com/ponycloud/python-sysfs) existe en función de esta respuesta. –

Cuestiones relacionadas