BlueThinking

think in blue

Desde python, como desde cualquier lenguaje de programación, podemos lanzar un comando externo al propio lenguaje de programación. Bien para cubrir algún aspecto que no provee el lenguaje o, la mayoría de las veces, para tapar nuestro desconocimiento del lenguaje.

En la mayoría de las ocasiones no es suficiente sólo con lanzar el comando. Queremos, además, poder procesar la salida recibida de alguna forma.

En python existen muchas formas de lanzar un comando externo, una de ellas es usando subprocess, que tiene algunas características particulares cuando el comando que lanzamos tiene pipes (tuberías).

En sistemas operativos entendemos por una tubería al procedimiento que permite enlazar la salida de un comando como entrada de otro:

In Unix-like computer operating systems (and, to some extent, Microsoft Windows), a pipeline is the original software pipeline: a set of processes chained by their standard streams, so that the output of each process (stdout) feeds directly as input (stdin) to the next one. Each connection is implemented by an anonymous pipe. Filter programs are often used in this configuration. Wikipedia

Un ejemplo sería, en un entorno linux, el siguiente comando que nos cuenta el número de ficheros y directorios que tenemos en un determinado directorio:

ls -l | wc -l

Curioso, ¿verdad?

Lo que hemos hecho ha sido ejecutar un ls -l (que muestra cada fichero y cada directorio en una línea) y el resultado, en vez de mostrarlo en pantalla como haría por defecto, se lo hemos pasado al comando wc -l que cuenta el número de lineas que ha recibido como entrada.

El ejemplo que queremos ver es el siguiente:

ipmitool sensor | grep deg

ipmitool es una herramienta que permite leer la información de los sensores de nuestro ordenador. Nuestro ordenador tiene una serie de sensores que nos informan del estado del sistema, la mayoría de ellos se refieren a la temperatura que hay en la CPU, en la tarjeta gráfica etc.

IPMItool is a utility for managing and configuring devices that support the Intelligent Platform Management Interface (IPMI) version 1.5 and version 2.0 specifications. IPMI is an open standard for monitoring, logging, recovery, inventory, and control of hardware that is implemented independent of the main CPU, BIOS, and OS.

Lo que hacemos con el comando anterior es mostrar la información de todos los sensores, y la salida, en vez de mostrarla en pantalla, la pasamos al comando grep que filtra sólo aquellas que tienen la palabra deg en algún lado: es decir el comando entero sólo muestra la información de aquellos sensores que tengan algo que ver con la temperatura (deg = grados )

La salida esperada sería algo como:

CPU 0 Temp       | 48.000     | degrees C  | ok    | na        | na        | na        | 93.000    | 95.000    | na        
CPU 1 Temp       | 50.000     | degrees C  | ok    | na        | na        | na        | 93.000    | 95.000    | na        
Ambient Temp0    | 39.000     | degrees C  | ok    | na        | na        | na        | 70.000    | 75.000    | na        
Ambient Temp1    | 47.000     | degrees C  | ok    | na        | na        | na        | 70.000    | 75.000    | na

La primera columna es el nombre del sensor, la segunda la temperatura actual. Las tres últimas informan de las temperaturas máximas que el sistema soportará antes de enviar mensajes de warning, de peligro o críticos, respectivamente.

Si queremos procesar esa salida de forma “elegante” para poder realizar algunas operaciones con ellos (guardar histórico, enviar correos…) debemos guardar esos datos en, por ejemplo, un array.

Por extraño que pueda parecernos, python no deja lanzar un comando con un pipe porque entiende, con toda la razón, que son dos procesos que deben enlazarse de la forma correcta:

from subprocess import Popen, PIPE


p1 = Popen(["ipmitool","sensor"], stdout=PIPE)
p2 = Popen(["grep", "deg"], stdin=p1.stdout, stdout = PIPE)
p1.stdout.close()
result = ( p2.communicate()[0] )
p1.wait()

Es de una lógica aplastante, pero no es nada intuitivo. Una vez que hemos adivinado eso, el resto es relativamente sencillo.

Conviene fijarse en con que gran habilidad hemos convertido la salida del proceso en líneas que luego son procesadas, a través del uso del readline y del split:

from subprocess import Popen, PIPE

p1 = Popen(["ipmitool","sensor"], stdout=PIPE)
p2 = Popen(["grep", "deg"], stdin=p1.stdout, stdout = PIPE)
p1.stdout.close()
result = ( p2.communicate()[0] )
p1.wait()

result = result.splitlines ()

for data in result:
   l = data.split ("|")
   nombre = l[0].strip()
   temperatura = l[1].strip()
   twarn = l[7].strip()
   tsoft = l[8].strip()
   tcrit = l[9].strip()

La ausencia de vida social, lejos del dolor y la agonía que me auguraba mi psicólogo, permite encontrar breves momentos de paz en estas cosas.

Sad but true.

0 Vote

Cuando trabajamos con Drupal 7 normalmente cargamos bastante el sistema durante el despliegue inicial: instalación de módulos, cargar el contenido inicial…

A veces, cuando estamos realizando esas operaciones, el servidor contra el que lo hacemos puede dar algún fallo por lo que debemos refrescar la página para volver a entrar.

Cada vez que entramos en el sistema Drupal guarda cierta información en las tablas de la base de datos para hacer más rápida la carga (una especie de caché del sistema). Si el servidor nos da algún fallo y refrescamos los datos de esas tablas pueden corromperse y el sistema nos devuelve de forma insistente ese mensaje de error:

drupal 7 PDOException: SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded;

No sé si existirá una opción mejor, pero una forma de arreglar ese problema es conectarse a la base de datos de Drupal (generalmente a través del administrador que nos provee el servicio de hosting, a través de la línea de comandos o bien con phpMyAdmin), y vaciar todas las tablas relacionadas con la cache del sistema:

TRUNCATE `cache` ;
TRUNCATE `cache_block` ;
TRUNCATE `cache_bootstrap` ;
TRUNCATE `cache_field` ;
TRUNCATE `cache_filter` ;
TRUNCATE `cache_form` ;
TRUNCATE `cache_image` ;
TRUNCATE `cache_menu` ;
TRUNCATE `cache_metatag` ;
TRUNCATE `cache_page` ;
TRUNCATE `cache_path` ;
TRUNCATE `cache_token` ;
TRUNCATE `cache_update` ;
TRUNCATE `cache_variable` ;
TRUNCATE `cache_views` ;
TRUNCATE `cache_views_data` ;
TRUNCATE `cache_widgets` ;
TRUNCATE `sessions` ;

Si al vaciar alguna de esas tablas obtenemos un error debemos reparar la tabla afectada.

REPAIR TABLE `tbl_name`;

No es peligroso eliminar los datos de esas tablas, ya que el contenido es creado de forma automática durante la navegación por el sitio, aún así siempre es conveniente realizar una copia de seguridad, eso no hace falta decirlo, ¿verdad?

 

1 Vote

Un hilo de Ariadna (Breadcrumb o migas de pan en inglés) es una técnica de navegación usada para desarrollar la interfaz gráfica de usuario. Tiene como objetivo que el usuario guarde una ruta de su ubicación dentro de programas o documentos. El término en inglés es breadcrumb, que proviene del cuento clásico Hansel y Gretel. En español, en vez del rastro de migas, se ha acuñado el término evocando el hilo que Ariadna dejó a Teseo para que encontrase el camino de salida en el laberinto del Minotauro. (fuente Wikipedia)

 

En resumen, un breadcrumb o hilo de Ariadna es ese texto que suele aparecer en la parte superior de algunas páginas web para mostrarnos el camino recorrido. De tal forma que si hemos entrado en un sitio buscando los drivers de nuestra tarjeta gráfica tendremos en la parte superior algo como: inicio / drivers / tarjeta gráfica / modelo. Siendo cada uno de los textos entre las barras un enlace que permite volver a la página de inicio, volver a la sección de drivers y sucesivamente.

En Drupal podemos generar de forma automática los breadcrumbs, pero el sistema lo hace a través de los elementos del menú que hayamos pulsado, para extender su funcionalidad podemos usar el módulo “Menu Breadcrumb“, que admite la posibilidad de añadir de forma automática al breadcrumb el menú al que pertenece la página actual junto con la página actual convertida en enlace.

Sin embargo, existen ocasiones en que esto no es suficiente y necesitamos tener más control sobre lo que se muestra. En el ejemplo anterior, nos gustaría que, hubiésemos llegado como hubiésemos llegado a ella, siempre que se muestre la página de descarga de una determinada tarjeta gráfica se mostrase, además, la ruta: inicio / drivers / tarjeta gráfica, y no sólo inicio / tarjeta gráfica. Es decir, que al usuario siempre le quede claro que se encuentra en esa sección y que puede volver a buscar otros modelos y, por supuesto, volver al inicio.

Para lograr ese comportamiento deberíamos conseguir que al mostrar una página determinada se adjuntase al breadcrumb la ruta anterior con sus enlaces correspondientes, algo que no hace por defecto.

La mejor opción para lograrlo es instalar un módulo y saber un poco, muy poco, de PHP.

En el ejemplo siguiente partiremos del siguiente supuesto:

  • Tenemos una página llamada productos cuya url es productos y con identificador node/30
  • En la página productos tenemos enlaces al productoA, productoB y productoC, que serán respectivamente node/25, node/30, node/45
  • Queremos que al mostrar productoA se muestre en el breadcrumb la ruta inicio / productos / productoA

 
Seguir leyendo continue reading…

0 Vote

En los últimos años Microsoft, en sus sistemas para servidores, parece haberse dado cuenta que encadenar todo la administración a una interfaz gráfica plagada de opciones no es la mejor solución para automatizar las operaciones más comunes.

Uno de los últimos intentos ha sido la inclusión de una interfaz de comandos llamada powershell. Para aquellos que vengan del mundo Unix no será nada revolucionado, e incluso puede ser frustrante cuando intentan usarla porque ha sido hecha al mejor estilo Microsoft: Un tipo de letra horrible, un autocompletar demente y una integración entre las diversas partes un tanto dudosas.

Para terminar de potenciar la interfaz han incluido un lenguaje de programación, de nuevo al estilo de los sistemas Unix, que permita automatizar las operaciones más comunes. Hemos visto en esta página algunos ejemplos sobre como usarlo.

El problema es que Microsoft tiene una capacidad innata para convertir en basura casi todas las buenas ideas que pasan por sus manos, y esto no es más que el siguiente hito en el camino. El sistema no es compatible entre diferentes versiones, hay demasiadas formas de hacer las cosas, y dependiendo desde donde lo ejecutes puedes obtener resultados distintos.

Creación automatizada de directorios y asignación de permisos desde línea de comandos para una lista de usuarios:

Un ejemplo típico de la utilidad de las herramientas de administración mediante consola es la siguiente: Imaginemos que nos han pasado una lista con cien usuarios, y ha sido redactada de la siguiente forma:

    Usuario1
    Usuario2
    Usuario3

Y que queremos, en uno de nuestros servidores, crear un directorio a modo de repositorio con el nombre de casa usuario en el que sólo tenga permiso de acceso dicho usuario.

Desde la interfaz gráfica deberíamos situarnos en el directorio, crear un directorio, ir a las propiedades del mismo y asignar los permisos. Son cien usuarios, pues eso mismo cien veces.

Los permisos se pueden asignar desde la interfaz gráfica, como hemos dicho en el punto anterior, o bien recurrir a la herramienta icacls desde la línea de comandos:

#Para quitar el acceso al directorio para todos los usuarios del dominio:
PS C:\> icacls directorio /remove \"Usuarios del dominio"
#Damos permiso total (full control) al usuario:
PS C:\> icacls directorio /grant usuario:F

Sin embargo, aun teniendo la herramienta icacls, el crear los directorios uno por uno y asignar los permisos uno a uno es una tarea farragosa e ingrata. Lo ideal sería poder recorrer la lista anterior y, para cada usuario, crear un directorio, borrar los permisos para todo el mundo y agregar los del usuario.

Para hacerlo con el lenguaje de programación de powershell necesitaríamos una manera de ejecutar un comando externo, algo que seguramente exista, pero de todas las opciones probadas no he logrado que funcione ninguna (seguramente por culpa mía, claro)

Al final la opción más sencilla resulto hacer un programa en python y ejecutar los comandos desde allí.

import sys
import os
from subprocess import call

def ensure_dir( d ):

    if not os.path.exists(d):
    print ("creando directorio %s") % ( d )
        os.makedirs(d)

#------------------------------------

if(len(sys.argv) > 1):
    fichero = sys.argv[1]
    print "Abriendo " + fichero
    f = open( fichero, "r" )
   
    for line in f:
        datos = line.strip ()
    if ( len ( datos )> 3 ):
            print ("---%s--") % (datos)
        dir = ".\\" + datos
        print dir
        ensure_dir ( dir )

        cmd = "icacls " +  datos + " /remove \"Usuarios del dominio\""
        os.system( cmd )

        cmd = "icacls " +  datos + " /remove Everyone"
        os.system ( cmd )

        cmd = "icacls " +  datos + " /grant " + datos + ":F"
        os.system ( cmd )
    f.close()    
else:
    print "Debes indicar el nombre del archivo"

El programa se encarga de abrir el fichero, recorrer cada línea, crear un directorio con ese nombre y asignar los permisos correspondientes. EL truco es que el nombre de usuario se llama exactamente igual que el directorio.

0 Vote