13.3 - Cosas Sencillas que se Hacen a Menudo

Aquí hay algunos ejemplos de automatización que son cosas simples que hacemos a menudo. Los administradores de sistemas Windows deben tener en cuenta que estos ejemplos están bastante centrados en Unix/Linux, pero los principios generales se aplican a todos los sistemas operativos.

La mayoría de los sistemas de línea de comandos tienen algún tipo de facilidad de alias. Esto le permite crear nuevos comandos a partir de otros anteriores. La sintaxis es diferente para cada tipo de línea de comandos. Unix tiene muchos lenguajes de shell (línea de comandos) diferentes, siendo los más populares bash y csh. Son diferentes en muchos aspectos, pero lo que notarás aquí (principalmente) es que bash requiere un signo de igualdad. Daré ejemplos para ambos shells.

Los ejemplos de bash funcionarán para cualquier shell modelado a partir del Bourne Shell original de Steve Bourne (/bin/sh), como el Korn Shell (/bin/ksh), y el Z Shell (/bin/zsh). Del mismo modo, los ejemplos de csh funcionarán para cualquier shell con raíces csh, incluyendo el shell Tenex C (/bin/tcsh).

Por ejemplo, a menudo necesito cambiar de directorio (cd) a un directorio específico que tiene una ruta muy larga. Este es un buen ejemplo de la utilidad de un alias.

Bash:

alias libro='cd ~tal/proyectos/libros/tiempo/capítulos'

csh:

alias libro 'cd ~tal/projects/books/time/chapters'  

Ahora puedo escribir libro siempre que quiera estar en el directorio correcto para trabajar en mi libro actual. Si empiezo a trabajar en un nuevo libro, actualizo el alias. (¡He estado escribiendo “libro” durante los últimos seis años más o menos!)

Esto no sólo ahorra teclear, sino que registra la ubicación para no tener que memorizarla. Una cosa menos que tengas que recordar es siempre una buena idea.

Para hacer que un alias sea permanente, tienes que añadir la línea anterior a tu archivo .profile, .bashrc (bash) o .cshrc (csh). Estos archivos sólo se leen al iniciar la sesión, por lo que hay que cerrar la sesión y volver a iniciarla, o bien, crear los archivos para leerlos de nuevo:

Bash:

. ~/.profile

csh:

source ~/.cshrc

(Nota: el comando de bash para leer un archivo es el punto, o punto).

Un alias puede contener varios comandos. Sepárelos con punto y coma. Aquí tenemos un ejemplo en el que necesitamos cambiar a un directorio concreto y establecer una variable de entorno en función de si estamos utilizando el sistema A o el sistema B:

Bash:

alias inva='cd ~tal/projects/inventory/groupa ; export INVSTYLE=A'
alias invb='cd ~tal/projects/inventory/groupb ; export INVSTYLE=B'

csh:

 alias inva 'cd ~tal/projects/inventory/groupa ; setenv INVSTYLE A'
 alias invb 'cd ~tal/projects/inventory/groupb ; setenv INVSTYLE B'

En lugar de usar un punto y coma, use && para indicar “Haga este siguiente comando sólo si el primero tuvo éxito”. Esto puede ser útil para protegerse contra la ejecución de un comando mientras está en el directorio equivocado. Por ejemplo, usted quiere ir a un directorio en particular y escribir una marca de tiempo en un archivo de registro. Sin embargo, si el cd falla (el servidor no está disponible), no querrá crear accidentalmente un archivo de registro en su directorio actual.

Bash:

alias rank='cd /home/rank/data && date >>.log'

csh:

alias rank 'cd /home/rank/data && date >>.log'

No intentes convertir un sistema operativo en otro. Los alias son geniales, pero no exageres. A menudo he visto a gente desarrollando docenas de alias para poder escribir comandos de DOS en Unix. Creo que esto es una mala idea. Nunca vas a aprender Unix de esa manera, y la próxima vez que estés en la máquina de otra persona y no tengas acceso a esos alias, estarás atascado.

Si hay nombres de host particulares que escribes una y otra vez, puedes ahorrar algo de tiempo creando alias. Por ejemplo, si a menudo tratas con una máquina llamada ramanujan.empresa.com, puedes crear un alias (un registro DNS CNAME) llamado ram.empresa.com. Así se teclea un poco menos.

El problema de esta técnica es que puede convertirse en una pesadilla de mantenimiento. Si la gente empieza a depender de ambos nombres, estás atascado manteniendo ambos nombres. Entonces, ¿cómo puedes crear un alias que sólo tú conozcas y que no moleste a otras personas?

Normalmente, si hay una máquina a la que accedo mucho, lo hago casi exclusivamente a través de Secure SHell (SSH). SSH es un reemplazo seguro (encriptado) de telnet y rsh. También puedes usarlo para copiar archivos (scp, un reemplazo de rcp), y muchos programas, como rsync, usan SSH. Unix SSH (OpenSSH y sus hermanos) te permite configurar alias de host para todos los usuarios de una máquina Unix o alias que son privados para ti.

Para afectar sólo a tus sesiones de SSH, añade los alias al archivo ~/.ssh/config. Para afectar a todos los usuarios del sistema, añada aliases a /etc/ssh_config o a /etc/ssh/ssh_config, dependiendo de cómo se haya configurado su sistema. En este ejemplo, creo un alias, es, para no tener que escribir www.everythingsysadmin.com todo el tiempo:

    Host es
        HostName www.everythingsysadmin.com

No sólo puedo usar ssh es donde solía escribir ssh www.everythingsysadmin.com, sino que el alias funciona para todos los comandos relacionados con SSH: scp, sftp, rsync, etc. De hecho, los scripts y programas que no puedo cambiar recogerán automáticamente esta configuración. Algunos ejemplos:

    $ ssh es
    $ scp archivo.txt es:/tmp/
    $ rsync es:/home/proyecto/alfa ~/proyecto/alfa

Necesito usar ssh es tan a menudo que en realidad he creado un alias de shell para reducir aún más mi escritura:

Bash:

  alias es='ssh es'

csh:

  alias es 'ssh es'

El resultado es que ahora puedo escribir es en la línea de comandos para entrar en la máquina, o puedo usar es para referirme a la máquina cuando se utiliza scp o rsync. Las mismas dos letras de cualquier manera. Genial, ¿no?

Es tentador crear alias de dos letras para cada servidor del mundo. Sin embargo, pronto te encontrarás pasando más tiempo recordando tu sistema de codificación que utilizándolo. Personalmente, me limito a unas pocas máquinas comunes a las que accedo vía SSH.

La página de manual ssh_config(5) enumera muchas otras opciones de configuración. Por ejemplo, hay una máquina a la que ocasionalmente accedo que requiere una combinación muy específica de opciones en la línea de comandos. (Es una versión casera del servidor SSH que no sólo no implementa todas las características sino que se confunde si intentas negociar algo que no entiende). El comando que tengo que teclear para hacerlo bien es

    $ ssh -x -o RSAAuthentication=yes -o PasswordAuthentication=yes -o
    ChallengeResponseAuthentication=no -1 peter.example.net

Podría haber configurado un alias de shell, pero en su lugar puedo modificar la configuración de SSH, y todos los sistemas que utilizan SSH harán lo correcto. Si un script que no puedo modificar utiliza SSH para llegar a esa máquina, esta configuración se seguirá utilizando.

Las líneas en mi archivo ~/.ssh/config se ven así

    Host peter.example.net
        ForwardX11 no
        RSAAuthentication sí
        PasswordAuthentication sí
        ChallengeResponseAuthentication no
        Compresión no
        Protocolo 1

Los clientes SSH para Windows tienden a tener una interfaz gráfica de usuario que le permitirá guardar la configuración del perfil que se utilizará para un host o hosts en particular.

Cuanto más aprendas sobre SSH, más podrás hacer con él. Hay muchos buenos libros y tutoriales en línea sobre los puntos más finos de SSH, como SSH, The Secure Shell: The Definitive Guide (O'Reilly). Si hay una cosa que todo administrador de sistemas debería, pero no sabe, sobre SSH, es cómo configurar claves públicas/privadas para eliminar de forma segura la necesidad de escribir contraseñas cuando se hace SSH de una máquina específica a otra.

Esta sección se aplica a los sistemas Unix/Linux. Los usuarios de Windows pueden omitirla.

Los sistemas Unix/Linux a menudo mantienen información crítica en archivos de texto plano que se editan a mano. A veces, después de editar un archivo, hay que ejecutar un comando para informar al sistema de que la información ha cambiado.

SSH al servidor correcto en una granja web cada vez

Suponga que tiene tres servidores: servidor1.ejemplo.com, servidor2.ejemplo.com y servidor3.ejemplo.com. Tienes muchos sitios web divididos entre ellos, y recordar qué sitio está en cada servidor se está convirtiendo en un lastre. ¿Está www.everythingsysadmin.com en el servidor 1 o en el 3? Crees que está en el 3, pero puede que alguien lo haya movido al 2 cuando te quedaste sin espacio en el disco. ¿Por qué intentar recordarlo? No es necesario crear un archivo de configuración, sólo hay que conectarse por SSH al nombre de host del sitio web. Por ejemplo, escriba ssh www.everythingsysadmin.com y pronto se encontrará en la máquina correcta. Vale, esto es bastante obvio, pero te sorprendería la frecuencia con la que la gente se olvida de que esto funciona.

Por ejemplo, después de editar /etc/aliases (parte de sendmail, Postfix y varios paquetes de agentes de transporte de correo), debes ejecutar el comando newaliases. Eso es bastante fácil de recordar, ¿verdad?

Después de editar el archivo de transportes de Postfix, ¿debe ejecutar el comando newtransports? No, eso sería demasiado obvio. Debes ejecutar postmap transports. Y está el comando m4 para ejecutar después de editar los archivos .m4, y así sucesivamente.

¿Quién tiene tiempo para recordar qué comando se utiliza después de editar qué archivo? Para esos detalles están los ordenadores.

make al rescate Puede que pienses en make como una herramienta de programación, el programa que ejecutas al compilar software. En realidad, te permite establecer cualquier tipo de relación que implique la necesidad de ejecutar un comando para actualizar un archivo si otro cambia.

make es una de las herramientas de administración de sistemas más poderosas jamás inventadas. He oído que los programadores también la encuentran útil.

make tiene más características que Liz Taylor ha tenido maridos, así que daré una breve introducción. (Si lees los dos primeros capítulos de la mayoría de los libros sobre make, sabrás el 99% de lo que necesitas para la mayoría de las tareas de administración de sistemas y 10 veces más de lo que saben tus compañeros de trabajo).

make lee un archivo de configuración llamado apropiadamente Makefile. En este archivo, encontrará recetas. Éstas instruyen a make sobre cómo hacer su trabajo.

Cada receta tiene el siguiente aspecto

  whole: parteA parteB parteC
      comando que crea whole

La receta comienza con el archivo que se va a crear, luego dos puntos, y después enumera los archivos necesarios para construir el archivo principal. En este ejemplo, la receta se refiere a whole y establece una relación entre éste y partA, partB y partC. Si la parteA, la parteB o la parteC se actualizan alguna vez, entonces tenemos que (re)ejecutar el comando que genera whole.

Un ejemplo del mundo real ayuda:

  aliases.db: aliases
      newaliases
      @echo Actualización de aliases Lista.

Este código significa que si aliases es cambiado, regenera aliases.db usando el comando newaliases. Entonces la receta emite “Actualización de aliases Lista” para anunciar su éxito.

Observe que la segunda y tercera línea de la receta están sangradas. Deben ser sangradas con un tabulador, no con varios espacios. ¿Por qué? Mi teoría es que el creador original de make quería castigarme cada vez que utilizo cortar y pegar en un sistema que convierte los tabuladores en espacios. Sin embargo, no me lo tomo como algo personal.

La actualización no se produce automáticamente. Tienes que ejecutar make para que ocurra:

  Servidor1# make aliases.db
  newaliases
  Terminada la actualización de aliases
  Servidor1#

Eso es todo: make leyó su archivo de configuración, averiguó que aliases era más reciente que aliases.db comprobando la marca de tiempo de los archivos, y determinó que ejecutar newaliases actualizaría aliases.db. Si lo ejecutamos de nuevo

  Servidor1# make aliases.db
  Servidor1#

No hay salida. ¿Por qué? Porque ahora las marcas de tiempo de los archivos indican que no hay trabajo que hacer: aliases.db es más nuevo que aliases. make es perezoso y calculará la cantidad mínima de trabajo requerido para hacer lo que le pides. Toma estas decisiones basándose en las marcas de tiempo de los archivos.

Aquí hay otro ejemplo de código de Makefile:

  archivo1.salida: archivo1.entrada
      comando1 <archivo.entrada >archivo.salida
  archivo2.salida: archivo2.entrada
      comando2 archivo2.entrada >$@

En el primer ejemplo, el comando a ejecutar utiliza stdin y stdout (redirección de archivos mediante < y >) para leer archivo.entrada y escribir archivo.salida. El segundo ejemplo es similar, pero el comando toma el nombre del archivo de entrada en la línea de comandos y redirige la salida a… ¿qué? Oh, $@ significa “El archivo que esta receta está creando”, o, en este caso, archivo2.salida. ¿Por qué no es algo simple como $me o $this? ¿Quién sabe? No tienes que usar $@, sólo te hace parecer más inteligente que tus compañeros de trabajo.

make sin parámetros en la línea de comandos ejecuta la primera receta del Makefile. Es tradicional nombrar la primera receta all y hacer que ejecute todas las recetas que se esperan por defecto. De esta manera, ejecutar make hace todas las recetas importantes. Puede que no sean literalmente todas las recetas, pero son todas las recetas que quieres hacer por defecto. Podría verse así:

  all: aliases.db access.db

make sin opciones se asegura de que aliases.db y access.db estén actualizados. Como no hay ningún comando como parte de all, no se creará ningún archivo llamado all. Así, make siempre piensa que all está desactualizado (“No existe” es igual a “Está desactualizado”). Pronto verás por qué esto es importante.

Recuerda que make es perezoso. Si access.db está desactualizado pero el otro archivo no lo está, simplemente ejecuta los comandos para actualizar access.db. De hecho, si actualizar access.db requiriera algo más, y eso requiriera algo más, y así sucesivamente, make haría muy inteligentemente sólo el trabajo mínimo requerido.

Además de todo, suelo incluir un par de comandos útiles:

    reload:
            postfix reload

    stop:
            postfix stop

    start:
            postfix start

Piensa en lo que esto significa. Si ejecuto make reload, make va a notar que no hay un archivo llamado reload, así que ejecutará postfix reload pensando que el comando creará un archivo llamado reload. Los engañé, ¿no es así? El comando que enumeré le dice a postfix que recargue su configuración. ¡Ese comando no crea un archivo llamado reload en absoluto! Por lo tanto, la próxima vez que ejecute make reload, make ejecutará el comando de nuevo. En otras palabras, si quieres que algo suceda siempre, asegúrate de que la receta simplemente no crea el archivo que make está esperando crear.

Con el código anterior en mi Makefile, puedo recargar, parar y arrancar postfix escribiendo make reload, make stop o make start, respectivamente. Si hay otras cosas que deben ser detenidas (por ejemplo, un servidor IMAP, un cliente de correo electrónico basado en la web, etc.), puedo incluir comandos para hacer esas cosas en las recetas. No tengo que recordar todos los comandos.

Este es un buen momento para señalar una pequeña mentira que dije antes. Dije que cada receta comienza con el archivo que va a ser creado, seguido de dos puntos, y luego enumera los archivos que componen el archivo principal. make no sabe si esos archivos realmente componen el archivo a ser creado. No hay manera de saberlo. Los elementos listados después de los dos puntos son realmente dependencias que deben estar actualizadas.

Aquí hay un simple Makefile de un sistema que ejecuta Postfix y que incluye recetas para reconstruir el índice de alias y acceso. Notará que en la parte superior hay algunas constantes (NEWALISES, PDIR, etc.) que se usan a lo largo del archivo. Además, una barra invertida (\) al final de la línea se utiliza para continuar las líneas largas:

    NEWALISES=/usr/sbin/newaliases
    PDIR=/etc/postfix
    POSTMAP=/usr/local/postfix/sbin/postmap

    # Los "comandos"

    all: $(PDIR)/aliases.pag $(PDIR)/aliases.dir \
            $(PDIR)/access.dir $(PDIR)/access.pag reload

    reload:
            postfix reload

    stop:
            postfix stop

    start:
            postfix start

    #
    # Cuando los alias cambian, genera los archivos .pag y .dir
    #
    $(PDIR)/aliases.pag $(PDIR)/aliases.dir: $(PDIR)/aliases
            $(NEWALIASES)

    #
    # Cuando el acceso cambia, genera los archivos .pag y .dir
    #
    $(PDIR)/access.dir $(PDIR)/access.pag: $(PDIR)/access
            $(POSTMAP) $(PDIR)/access

Ahora puedo editar cualquiera de los alias o access y escribir make. No tengo que recordar que los comandos para actualizar los índices son muy diferentes. Y no tengo que recordar decirle a postfix que recargue su configuración cada vez porque la receta all incluye eso. El reload al final de all activará esa receta cada vez.

make también puede ser útil para mantener los archivos de varios servidores actualizados. Por ejemplo, supongamos que el archivo de alias en nuestro ejemplo necesita ser el mismo en ambos servidores de correo electrónico. Decidimos que vamos a actualizar el archivo en este servidor, y empujarlo al servidor2. La receta podría ser la siguiente

    push.aliases.done: $(PDIR)/aliases
        scp $(PDIR)/aliases servidor2:$(PDIR)/aliases
        touch $@

Empujamos el archivo al servidor2 usando scp, luego tocamos un archivo llamado push.aliases.done. Dado que este archivo se crea después de la copia exitosa del archivo, podemos construir recetas para que el push sólo se haga si es absolutamente necesario. También podemos forzar que el archivo se vuelva a copiar simplemente borrando el archivo push.aliases.done y escribiendo make. tradicionalmente, hay una receta llamada clean que borra todos los archivos *.done y otros archivos generados por la máquina.

No hay nada especial en los archivos que terminan con .done. Simplemente se acostumbra a nombrar o marcar los archivos con .done al final.

He aquí un ejemplo completo. Hay dos archivos que necesitan ser indexados si cambian: alias y access. Si cualquiera de ellos ha sido reindexado, se le dice a postfix que lo recargue. También son empujados al servidor 2 si cambian. Finalmente, el comando cd /etc && make es enviado al servidor2 si y sólo si uno o más de los archivos han sido empujados a él.

Construyendo cuidadosamente las recetas con las dependencias apropiadas, y tocando los archivos *.done donde sea necesario, make hará la mínima cantidad de trabajo para actualizar el sistema:

#
    # Makefile for server1
    #

    NEWALISES=/usr/sbin/newaliases
    PDIR=/etc/postfix
    POSTMAP=/usr/local/postfix/sbin/postmap

    #
    # High-level "commands"
    #
    all: aliases.done access.done reload_if_needed.done push

    push: push.done

    reload:
        postfix reload

    stop:
        postfix stop

    start:
        postfix start

    reload_if_needed.done: aliases.done access.done
        postfix reload
        touch reload_if_needed.done

    clean:
        rm -f \
            $(PDIR)/aliases.pag $(PDIR)/aliases.dir \
            $(PDIR)/access.dir $(PDIR)/access.pag \
            push.aliases.done push.access.done reload_if_needed.done

    #
    # Recipes for particular files that need indexing/regeneration
    #

    # When aliases changes, generate the .pag and .dir files

    aliases.done: $(PDIR)/aliases.pag $(PDIR)/aliases.dir

    $(PDIR)/aliases.pag $(PDIR)/aliases.dir: $(PDIR)/aliases
        $(NEWALIASES)

    # When access changes, generate the .pag and .dir files

    access.done: $(PDIR)/access.dir $(PDIR)/access.pag

    $(PDIR)/access.dir $(PDIR)/access.pag: $(PDIR)/access
            $(POSTMAP) $(PDIR)/access


    #
    # pushes
    #

    push.done: push.aliases.done push.access.done
        ssh server2 "cd /etc && make"
        touch $@

    push.aliases.done: aliases.done
        scp $(PDIR)/aliases server2:$(PDIR)/aliases
        touch $@

    push.access.done: access.done
        scp $(PDIR)/access server2:$(PDIR)/access
        touch $@

Este Makefile es un buen punto de partida para que lo use en sus sistemas. Es bastante sofisticado porque hacemos cosas para asegurarnos de que Postfix no se recargue a menos que sea absolutamente necesario.

Con un Makefile como este, ya no tiene que recordar una multitud de comandos y cuáles deben ser usados para cada archivo actualizado. Nunca tiene que preocuparse por olvidarse de escribir un comando. Muchos procedimientos complicados se reducen a

  1. Editar el archivo apropiado.

  2. Escribir make.

make puede ser la herramienta definitiva para unir muchos procesos automatizados más pequeños. Una vez, tuve que fusionar los procesos y procedimientos de tres grandes redes en una sola. Cada red tenía una forma diferente de gestionar sus alias, hosts y otros archivos administrativos. Mientras aprendía los procedimientos de cada red, construí un Makefile específico para el servidor maestro de esa red. Los nombres de las recetas de alto nivel eran los mismos en las tres redes, pero los comandos que ejecutaban para realizar el trabajo eran específicos de cada red.

La estrategia era crear un nuevo servidor maestro que eventualmente reemplazaría a todos los servidores heredados. Inicialmente, el Makefile del nuevo maestro simplemente iniciaba un make en los tres maestros heredados a través de rsh (esto fue mucho antes de ssh). Luego migré las recetas al nuevo maestro de una en una. Por ejemplo, primero decidí que el nuevo maestro sería la única fuente para el archivo de alias. Fusioné los archivos de alias de las tres redes heredadas y puse el resultado en el nuevo maestro. Una vez probado allí, añadí recetas en el nuevo maestro para empujar ese archivo fusionado a los maestros heredados como si fuera propio. Continué este proceso para cada archivo o base de datos.

Como cada cambio era pequeño y específico, podía probarlo de forma incremental. Después de literalmente cientos de pequeños cambios, todos los servidores estaban “cantando del mismo cancionero”. En ese momento, fue fácil eliminar los maestros heredados y dejar que el nuevo maestro fuera el maestro autorizado para todos los clientes.

Cualquier archivo que se envíe automáticamente a otros servidores debe tener siempre un comentario en la parte superior del archivo que advierta a otros administradores del sistema de dónde procede el archivo y dónde editarlo.

Esta es la advertencia que utilizo:

    # ESTE ARCHIVO SE MANTIENE EN: servidor1.ejemplo.com
    # Edítalo con este comando: xed archivo.txt
    # Si editas este archivo en cualquier otra máquina,
    # se sobrescribirá.  ¡TENGA CUIDADO!

Ya que en la nota anterior se mencionó xed, debo explicar lo que es. Hay muchos programas llamados xed, pero este se puede encontrar en http://www.nightcoder.com/code/xed. Este programa llama al editor que usas habitualmente ($EDITOR puede ser vi, pico, emacs, etc.) después de bloquear el archivo. Es una necesidad para cualquier sitio que tenga múltiples administradores de sistemas trabajando en la misma máquina. Si estás usando RCS para rastrear los cambios en un archivo, hace todo el trabajo de “check in” y “check out” por ti. Esto le permite deshacer infinitamente y tener un archivo de registro de quién cambió qué. Si encuentras que un sistema ha estado actuando de forma extraña durante el último mes, sólo tienes que comprobar el registro para ver quién cambió el archivo hace un mes y, bueno, sé amable, todos cometemos errores.


Volver al índice