<!doctype article PUBLIC "-//Davenport//DTD DocBook V3.0//EN" []>
<article lang="es">
  <artheader>
    <date>2001-07-09</date>
    <authorgroup>
      <author><firstname>Esteban</firstname> <surname>Manchado
      Velázquez</surname></author>
      <author><firstname>Miguel</firstname> <surname>Armas del
      Río</surname></author>
    </authorgroup>
    <title>PICA: Perl Installation and Configuration Agent</title>
    <subtitle>Una solución inteligente para administración de sistemas</subtitle>
  </artheader>
  <!-- toc></toc -->

  <sect1>
    <title>Introducción</title>

    <para>PICA es una pequeña herramienta escrita en Perl para ayudar a los
    administradores de sistemas a mantener coherente la configuración de sus
    máquinas. Además de en el lenguaje Perl, PICA se basa en muchas ideas de
    la herramienta PIKT, y en SSH, para enviar todos los datos de unas
    máquinas a otras de forma segura.</para>


    <sect2>
      <title>¿Por qué escribimos PICA?</title>

      <para>Necesitábamos una forma de mantener una copia de la configuración
      de los servidores en una de las máquinas, para luego poder copiar los
      ficheros necesarios a las que hiciera falta. Hasta el momento estábamos
      usando PIKT, pero había muchas cosas que no nos gustaban.  La idea
      encajaba perfectamente con nosotros, pero necesitábamos más potencia,
      más flexibilidad, más seguridad y más comodidad. Las alternativas
      tampoco nos gustaban por diferentes razones, como veremos más
      adelante.</para>
    </sect2>


    <sect2>
      <title>¿Por qué no PIKT?</title>

      <para>PIKT es un programa escrito en C cuyo cometido es copiar ficheros
      a máquinas remotas, instalar alarmas y ejecutar órdenes
      remotamente. Es una herramienta bastante útil para administradores de
      sistemas, y nosotros la usamos durante un tiempo, pero decidimos
      escribir PICA y dejar de usar PIKT por varias razones, entre las que
      destacan:</para>

      <itemizedlist>
	<listitem><para>Uso de <emphasis>portmapper</emphasis> para las
	comunicaciones, por el historial de problemas de seguridad y la
	apertura de un servicio que no usábamos para nada
	más.</para></listitem>
	<listitem><para>Imposibilidad de enviar ficheros
	binarios.</para></listitem>
	<listitem><para>Sistema de condiciones muy pobre.</para></listitem>
	<listitem><para>Imposibilidad de generar partes de los ficheros
	dinámicamente.</para></listitem>
	<listitem><para>Varios fallos graves en el propio programa, debidos en
	parte al perfil de su creador (administrador de sistemas y no
	programador).</para></listitem>
	<listitem><para>Falta de una forma sencilla de distribuir ficheros sin
	tener que adaptarlos a una sintaxis determinada.</para></listitem>
	<listitem><para>Necesidad de decidir de antemano qué servidores iban a
	tener ficheros distribuidos automáticamente, ya que hay que instalar
	un cliente en cada una de estas máquinas.</para></listitem>
	<listitem><para>En general, un enfoque muy complejo, difícil de
	entender y un programa difícil de modificar para resolver un problema
	muy simple.</para></listitem>
      </itemizedlist>
    </sect2>

    <sect2>
      <title>Alternativas a PIKT</title>

      <para>Algunas de las alternativas a PIKT (y PICA) son
      <application>cfengine</application>, <application>arusha</application>,
      <application>big sister</application>, y
      <application>gap</application>. Ninguna de ellas satisfacía todas
      nuestras necesidades de administración, o resultaron demasiado
      complicadas para el problema que queríamos resolver.</para>

      <para>Sin duda, y obviando PIKT, <application>cfengine</application> es
      la herramienta más parecida a PICA. Sus inconvenientes: tener que
      aprender muchos conceptos nuevos, compuesto por varios programas
      (instalación más compleja) y necesidad de aprender un lenguaje de
      configuración específico para usar la herramienta. Además, aparentemente
      no permite copiar los ficheros variando su contenido según la máquina o
      cualquier otra condición.</para>

      <para><application>Arusha</application> no termina de resolver nuestros
      problemas, por ser un &laquo;marco&raquo; en el que trabajar y construir
      las soluciones de administración. Por si fuera poco, necesita también
      conocer un lenguaje de configuración específico (en XML) para poder
      usarlo. PICA da una solución mucho más simple, más sencilla de aprender
      y que puede usarse al poco tiempo de instalar el programa.</para>

      <para><application>Big sister</application> es una aplicación de
      monitorización, que nada tiene que ver con PICA: ambas herramientas son
      complementarias y podrían usarse conjuntamente.</para>

      <para>Por último, <application>gap</application> es un proyecto
      demasiado ambicioso para nuestros problemas diarios. Al igual que
      algunas de las otras alternativas, necesita aprender su forma de
      trabajo, y parece más enfocado hacia la monitorización y ejecución
      remota que a la simple copia de ficheros.</para>
    </sect2>

    <sect2>
      <title>¿Dónde conseguir PICA?</title>

      <para>La página oficial de PICA está en SourceForge, en la URL
      <ulink url="http://pica.sf.net">http://pica.sf.net</ulink>, y se
      distribuye por la licencia GPL.  Hay disponibles paquetes Debian y RPM,
      además del paquete original <emphasis>.tar.gz</emphasis>.</para>
    </sect2>
  </sect1>

  <sect1>
    <title>Fundamentos de PICA</title>

    <para>Teniendo en cuenta nuestra experiencia usando PIKT, queríamos
    intentar evitar los errores de éste en nuestro nuevo proyecto. Por esta
    razón, aprovechamos ideas del PIKT, pero lo diseñamos todo desde cero.
    Usamos un lenguaje de programación diferente (Perl), y unos ficheros de
    configuración y de entrada con una sintaxis completamente distinta,
    diseñada acorde con nuestros objetivos. Queríamos mantener la filosofía
    del PIKT, pero cambiar el enfoque y la mentalidad en cuanto a las
    herramientas.</para>

    <sect2>
      <title>Principios de diseño</title>

      <para>Los principios de diseño de PICA son:</para>

      <orderedlist>
	<listitem><para>Deben usarse herramientas existentes que funcionen
	bien. De ahí que se use SSH para todas las
	transferencias.</para></listitem>
	<listitem><para>La seguridad tiene que tenerse en cuenta. Toda la
	información va cifrada, y no se requiere que PICA tenga permisos
	especiales para hacer su trabajo.</para></listitem>
	<listitem><para>Todo debe ser lo más flexible posible, para no tener
	que estar haciendo extensiones de la sintaxis o de la funcionalidad
	una y otra vez.</para></listitem>
	<listitem><para>La simplicidad y linealidad son buenas a largo
	plazo. Por ello, todos los ficheros de configuración se preprocesan
	antes de leerse, y todas las condiciones del preprocesador de PICA no
	son más que expresiones en Perl genéricas. Los casos particulares
	comunes se tratan con funciones en Perl declaradas visiblemente en un
	paquete para tal efecto.</para></listitem>
      </orderedlist>
    </sect2>

    <sect2>
      <title>Conceptos importantes en PICA</title>

      <para>A la hora de trabajar, PICA se apoya en los siguientes
      conceptos:</para>

      <itemizedlist>
	<listitem><para>Máquinas. Para PICA, conceptualmente las máquinas
	siempre son remotas, es decir, todo se copia siempre mediante órdenes
	<command>ssh</command>.</para></listitem>
	<listitem><para>Objetos. Son los ficheros que PICA distribuye a las
	máquinas. Estos ficheros pueden ser ficheros normales o
	<emphasis>alarmas</emphasis>, que tienen un tratamiento especial en
	algunos casos. Hablaremos de éstas más tarde.</para></listitem>
	<listitem><para>Grupos. Podemos agrupar tanto las máquinas como los
	objetos con nombres fáciles de manejar. Además, las alarmas son grupos
	implícitos, que pueden contener otros objetos (ficheros normales, nunca
	otras alarmas). Estos objetos se tratan como dependencias, es decir,
	siempre que se instale esa alarma deben instalarse también las
	dependencias.</para></listitem>
      </itemizedlist>
    </sect2>
  </sect1>

  <sect1>
    <title>Posibilidades de PICA</title>

    <para>PICA se diseñó para resolver los siguientes problemas:</para>

    <itemizedlist>
      <listitem><para>Copia de ficheros de una máquina central al resto. Los
      ficheros debían tener condicionales y alguna forma genérica de decidir
      qué iba a formar parte del contenido, dependiendo de la máquina donde
      fuera a instalarse y de otros parámetros no decididos de antemano por
      nosotros.</para></listitem>
      <listitem><para>Ejecución remota de órdenes, tanto distribuidas con el
      programa como arbitrarias, instaladas en la máquina
      destino.</para></listitem>
      <listitem><para>Gestión de alarmas en cada máquina. Entendemos por
      alarmas pequeños programas que comprueban el estado del sistema y avisan
      de cualquier anomalía, y que optativamente lo
      resuelven.</para></listitem>
    </itemizedlist>

    <para>Todo esto se hace a petición explícita del administrador. Es decir,
    que cada vez que se quiere copiar, ejecutar, borrar o listar un objeto, el
    administrador llama desde la línea de órdenes a PICA con los parámetros
    apropiados (veremos la sintaxis de llamada más adelante). Para funcionar,
    PICA <emphasis>no</emphasis> necesita instalar ningún programa en las
    máquinas a las que se va a copiar ficheros, o sobre las que se va a
    actuar. El único requisito es tener un servidor SSH instalado (y, a estas
    alturas, ¿qué servidor que nos preocupe no tiene ya el SSH?).</para>

    <sect2>
      <title>Opciones de llamada</title>

      <para>Las operaciones que PICA puede ejecutar son:</para>

      <itemizedlist>
	<listitem><para><emphasis>Instalación</emphasis> de cualquier objeto o
	grupo de objetos (ficheros o alarmas). Los ficheros a copiar se llaman
	<emphasis>ficheros de distribución</emphasis>, y pueden contener
	directivas para ser preprocesados. Por defecto, los ficheros de
	distribución se buscan en el directorio <literal>$picasrc</literal>
	especificado en el fichero de configuración
	<filename>pica.conf</filename>.</para></listitem>
	<listitem><para><emphasis>Ejecución</emphasis> de un objeto
	remotamente, como si fuera una orden del sistema (PICA busca la ruta
	correcta en la definición del objeto), o una orden arbitraria que esté
	instalada en la máquina remota (muy útil para actualizar la
	configuración de un servicio que se está ejecutando).</para></listitem>
	<listitem><para><emphasis>Borrado</emphasis> de
	objetos.</para></listitem>
	<listitem><para><emphasis>Cálculo de diferencias</emphasis> de un
	objeto (diferencia entre la versión que se instalaría y la que hay
	realmente en la máquina).</para></listitem>
	<listitem><para><emphasis>Listado</emphasis> de objetos. PICA puede
	listar los objetos que hay instalados en una máquina determinada, para
	saber si están instalados y para comprobar sus permisos y
	propietarios.</para></listitem>
      </itemizedlist>

      <para>Por otro lado, hay tres opciones generales de PICA, aplicables a
      todas las operaciones:</para>

      <itemizedlist>
	<listitem><para>Modo de depuración. PICA informará de todo lo que hace
	a medida que lo va haciendo, y deja los ficheros de configuración
	preprocesados en el directorio temporal. Además, <emphasis>no ejecuta
	ninguna orden, ni instala ni borra ningún fichero</emphasis>, sólo
	imprime en pantalla qué debería ejecutar en cada
	momento.</para></listitem>
	<listitem><para>Simulación. Esta opción permite simular, sin producir
	realmente ningún resultado, cualquier acción. Puede informar de
	errores, e imprime las órdenes que ejecutaría en condiciones normales.
	Es similar a la opción <literal>-n</literal> del programa
	<application>make</application>.</para></listitem>
	<listitem><para>Verbosidad. Imprime en pantalla mucha más información
	que de costumbre. Conjugando esta opción con la anterior se puede
	conseguir algo parecido a la de depuración, pero sin dejar ficheros en
	el directorio temporal ni cargar <emphasis>tanto</emphasis> la
	pantalla.</para></listitem>
      </itemizedlist>
    </sect2>
  </sect1>

  <sect1>
    <title>Configuración de PICA</title>

    <para>PICA tiene actualmente tres ficheros de configuración. Su sintaxis es
    parecida a la de los ficheros de DNS, por ser clara y legible y resultar
    familiar a los administradores de sistemas. En uno especificamos algunos
    datos necesarios para el propio ejecutable de PICA, y en los otros dos
    especificamos las máquinas y los objetos que vamos a manejar,
    respectivamente. Los ficheros se llaman <filename>pica.conf</filename>,
    <filename>hosts.conf</filename> y <filename>objects.conf</filename>.
    Aunque no es importante para entender el funcionamiento general de PICA,
    sí es importante a la hora de usarlo saber que los ficheros se leen en ese
    orden.</para>

    <sect2>
      <title><filename>pica.conf</filename></title>

      <para>En este fichero se especifican las rutas de varios ejecutables que
      PICA necesita, algunos directorios locales importantes para el programa
      (dónde van los ficheros temporales, por ejemplo) y una lista de
      directorios que no deben borrarse:</para>

      <example>
      <title>Ejemplo de <filename>pica.conf</filename></title>
      <programlisting>
# pica.conf

defaults {
   # Directorios (locales) importantes para el ejecutable
   picaroot    = /var/lib/pica;  # Raíz de los ficheros para PICA
   picatmp     = /var/lib/pica/tmp; # Ficheros temporales
   # Donde están los ficheros a distribuir
   picasrc     = /var/lib/pica/src;
   # Ficheros de inclusión del preprocesador
   picainclude = /var/lib/pica/include;

   # Rutas de algunos programas usados por PICA
   sshpath   = '/usr/bin/ssh -q';  # Ruta al ssh (y opciones)
   diffpath  = '/usr/bin/diff';
   tarpath   = '/bin/tar';
   rsyncpath = '/usr/bin/rsync';

   # Directorios protegidos (nunca se borrarán ni se cogerán
   # como directorios temporales)
   protecteddirs {
      /,
      /bin,
      /usr/bin,
      /lib,
      /usr/lib
   }
}
      </programlisting>
      </example>
    </sect2>

    <sect2>
      <title><filename>hosts.conf</filename></title>

      <para>El fichero de descripción de máquinas permite especificar los
      nombres de las que vamos a manejar y sus propiedades, junto con la
      definición de los posibles grupos que queramos (para facilitarnos el
      referirnos a éstas al llamar a PICA). Por defecto, se intentará conectar
      con las máquinas por el nombre que le demos en el fichero. Si se quiere
      poner un nombre &laquo;lógico&raquo; diferente del nombre real de la
      máquina, se puede usar la propiedad <literal>fqdn</literal>.</para>

      <example>
      <title>Ejemplo de <filename>hosts.conf</filename></title>
      <programlisting>
# hosts.conf

# Valores por defecto
defaults {
   method      =  'tar'; # método de copia (tar, rsync or ssh)

   # Variables globales
   vars {
      docdir  = '/var/www/html/sysadm';
   }
}

# Definición de máquina
host mimaquina;
host miotramaquina {
   method = ssh;
   fqdn   = nombre.completo.net;
}

# Definición de grupo
hostgroup migrupo {
    members { mimaquina, miotramaquina }
}

hostgroup miotrogrupo {
    members { miotramaquina }
}
      </programlisting>
      </example>
    </sect2>

    <sect2>
      <title><filename>objects.conf</filename></title>

      <para>El fichero de objetos probablemente será el que modifiquemos con
      más frecuencia, y desde luego es el que tiene la sintaxis más
      completa. Al igual que en el fichero de máquinas, especificamos la lista
      de objetos que podemos distribuir con sus propiedades y los grupos que
      queramos crear (aunque se declaran de forma diferente, ver
      ejemplo).</para>

      <example>
      <title>Ejemplo de <filename>objects.conf</filename></title>
      <programlisting>
# objects.conf

# Inclusión de ficheros
#include &lt;pifia.conf&gt;

# Valores por defecto
defaults {
    uid = 0;
    gid = 0;
    perms = 644;
    verbatim = 0;  # Si vale 1 no se aplica el preprocesador
                   # antes de copiar
}

# Ficheros de prueba
file pica-rules {
    path = '/var/lib/pica/rules'; # Donde se instalan en la máquina
                                  # remota
    source = 'pica-rules';	# Donde está el "fuente" localmente

    # Variables locales para el fichero (se podrán sustituir
    # en el fichero de distribución, ver ejemplos del preprocesador
    # más adelante)
    vars {
       myvar         = 'foo';
       limit         = '2';
       mythirdvar    = 'enough';
    }
}

# Ficheros de autentificación RSA con SSH
group sshauth {
   file auth_keys {
      source = 'SSHAuth/authorized_keys';
      path   = '/root/.ssh/authorized_keys';
      perms  = '600';
   }
   # SSH v.2
   file auth_keys2 {
      source = 'SSHAuth/authorized_keys2';
      path   = '/root/.ssh/authorized_keys2';
      perms  = '600';
   }
}
      </programlisting>
      </example>
    </sect2>
  </sect1>

  <sect1>
    <title>Usos comunes de PICA</title>

    <para>A continuación de presentan algunos de los casos comunes de uso de
    PICA, no sin antes explicar brevemente el formato de la llamada.</para>

    <sect2>
      <title>Formato general de la llamada a PICA</title>

      <para>En general, el formato de una llamada a PICA se compone de: una
      operación y opciones generales, una lista de objetos sobre los que operar
      y una lista de máquinas sobre las que operar. La sintaxis es muy similar
      a la del PIKT, por aquello de no tener que aprender una nueva sintaxis, y
      porque nos pareció apropiada (al fin y al cabo,
      <emphasis>queríamos</emphasis> aprovechar todo lo posible del
      PIKT).</para>

      <para>Las opciones y la operación van precedidas de un guión, al estilo
      de las opciones normales de UNIX. Pueden agruparse o separarse, por
      legibilidad.</para>

      <para>Para especificar las listas de máquinas y objetos hay toda una
      sintaxis de aritmética, también tomada prestada del PIKT. Debido a esta
      aritmética, podemos ir sumando y restando máquinas, objetos y grupos de
      ambos. Para sumar o restar máquinas, precedemos la lista con
      <literal>+H</literal> o <literal>-H</literal>, y para sumar o restar
      objetos (ficheros o alarmas), <literal>+F</literal> o
      <literal>-F</literal>.</para>
    </sect2>

    <sect2>
      <title>Ejemplos de llamadas a PICA</title>

      <para>Algunos ejemplos terminarán de aclarar el uso de la aritmética de
      objetos y máquinas. Empecemos por el caso más común de todos, la
      instalación (copia) de un objeto (<literal>pica-rules</literal>) en una
      máquina (<literal>demiurgo</literal>):</para>

      <example>
	<title>Llamada a PICA (instalación de <literal>pica-rules</literal> en
	<literal>demiurgo</literal>)</title>

	<literallayout>
	  pica -i +F pica-rules +H demiurgo
	</literallayout>
      </example>

      <para>Supongamos ahora que tenemos definido un grupo de máquinas con los
      servidores DNS (<literal>dnsservers</literal>) a las que queremos copiar
      todos los ficheros definidos para esas máquinas. El problema es que hay
      dos máquinas pertenecientes al grupo que están en pruebas o apagadas y
      por esta vez no vamos a procesarlas (<literal>w2k</literal> y
      <literal>w98</literal>).  En ese caso, podríamos perfectamente
      &laquo;restarlas&raquo; del grupo con algo como:</para>

      <example>
	<title>Resta de dos máquinas a un grupo</title>

	<literallayout>
	  pica -i +F all +H dnsservers -H w2k w98
	</literallayout>
      </example>

      <para>Nótese que en este ejemplo acabamos de introducir un concepto
      nuevo: el de grupos implícitos. Para hacernos la vida más fácil, PICA
      define algunos grupos implícitamente. Tanto para máquinas como para
      objetos está definido el grupo
      <emphasis><literal>all</literal></emphasis>, que se refiere a todas las
      máquinas/objetos (depende del contexto). También vale la pena comentar
      que los espacios de nombres de los objetos y las máquinas son
      completamente independientes, así que podemos tener
      <emphasis>tanto</emphasis> una máquina (o grupo de máquinas) como un
      objeto (o grupo de objetos) llamado
      &laquo;<literal>dns</literal>&raquo;.  Sin embargo, para evitar
      confusiones suele ser una buena costumbre no repetir nombres.</para>

      <para>Si, en vez de copiar un objeto, queremos comparar la versión que
      se instalaría y la que está realmente instalada en todas las máquinas
      definidas, podríamos usar lo siguiente:</para>

      <example>
	<title>Comparación de un objeto</title>

	<literallayout>
	  pica -f +F fichero-importante +H all
	</literallayout>
      </example>

      <para>La salida será un <application>diff</application> unificado entre
      ambas versiones.</para>

      <para>El borrado de objetos es igual de simple, pero usando la opción
      <literal>-t</literal>:</para>

      <example>
	<title>Borrado de objetos</title>

	<literallayout>
	  pica -t +F fichero-menos-importante +H all
	</literallayout>
      </example>

      <para>En la ejecución hay dos casos: por un lado, podemos ejecutar un
      objeto de PICA que sea una orden (si tiene permiso de ejecución y está
      instalado); por otro lado, podemos ejecutar órdenes instaladas en la
      máquina remota aunque no estén declaradas en
      <filename>objects.conf</filename>. Por ejemplo, supongamos que uno de
      los objetos que distribuimos es un programa llamado
      <application>postupdate</application> que actualiza la configuración del
      <application>postfix</application>. Si lo tuviéramos declarado como
      objeto de PICA, aunque no se instalara en un directorio dentro de la
      ruta de búsqueda de ejecutables, podríamos ejecutarlo en todas las
      máquinas del grupo <literal>mailservers</literal> escribiendo</para>

      <example>
	<title>Ejecución del objeto <literal>postupdate</literal> en los
	componentes del grupo <literal>mailservers</literal></title>

	<literallayout>
	  pica -x +F postupdate +H mailservers
	</literallayout>
      </example>

      <para>Si, por el contrario, lo único que queremos es ejecutar una orden
      cualquiera de la máquina (incluso con parámetros), podemos escribir algo
      como lo siguiente:</para>

      <example>
	<title>Ejecución de órdenes remotas con parámetros</title>

	<literallayout>
	  pica -x +F "killall netscape" +H alumnos-3
	</literallayout>
      </example>

      <para>La razón de poner las comillas es que PICA interpreta diferentes
      parámetros como distintas órdenes a ejecutar. Si no pusiéramos comillas,
      intentaría ejecutar <application>killall</application> sin parámetros y
      la aplicación <application>netscape</application> en remoto.</para>

      <para><emphasis>Todo</emphasis> el manejo de PICA se basa en estos
      ejemplos. Podemos añadir objetos que nos solucionen problemas u objetos
      que sean órdenes para ejecutar remotamente, pero todo lo haremos con la
      instalación y ejecución remota. Incluso las alarmas, que veremos en el
      siguiente apartado, se basan en estos principios.</para>
    </sect2>
  </sect1>

  <sect1>
    <title>Gestión de alarmas: PIFIA</title>

    <para>Llamamos &laquo;alarmas&raquo; a pequeños programas que comprueban el
    estado de los servicios del sistema y avisan de las posibles anomalías,
    intentando quizás recobrar el estado normal. Todos los ficheros y
    convenciones de PICA en torno a las alarmas reciben el nombre de PIFIA
    (PICA Framework for Integrated Alarms).</para>

    <para>Las alarmas se instalan como ficheros normales en las máquinas
    remotas, aunque tienen algunas propiedades adicionales y la forma de
    declararlas es diferente a la de los objetos corrientes. El trato
    homogéneo de todos los objetos tiene varias ventajas:</para>

    <orderedlist>
      <listitem><para>No añadimos conceptos nuevos ni el administrador tiene
      que recordar otra sintaxis.</para></listitem>
      <listitem><para>Pueden instalarse diferentes versiones en distintas
      máquinas, si fuera necesario o conveniente.</para></listitem>
      <listitem><para>Evitamos un trato especial a las alarmas, que de esta
      forma pueden entenderse como simples ficheros. Esto facilita la creación
      de programas de gestión de alarmas (por nosotros y por terceros) y
      facilita que, en caso de problemas, los administradores puedan
      cambiarlas, moverlas, borrarlas, o manipularlas de cualquier forma
      manualmente.</para></listitem>
    </orderedlist>

    <para>Una vez copiadas en la máquina destino se ejecutan periódicamente
    (como un trabajo <emphasis>cron</emphasis> normal y corriente), evitando
    así la dependencia de la conexión con el servidor &laquo;principal&raquo;,
    del que se copiaron originalmente las alarmas.</para>

    <sect2>
      <title>Declaración de las alarmas</title>

      <para>En el apartado de configuración ya hemos visto cómo declarar un
      objeto. Las diferencias entre los objetos normales y las alarmas
      son:</para>

      <itemizedlist>
	<listitem><para>Las alarmas tienen una propiedad obligatoria
	adicional, <literal>priority</literal>, que indica la frecuencia con
	la que se ejecuta. La prioridad puede ser
	&laquo;<literal>Emergency</literal>&raquo;,
	&laquo;<literal>Urgent</literal>&raquo; y
	&laquo;<literal>Warning</literal>&raquo;.</para></listitem>
	<listitem><para>En vez de la palabra <literal>file</literal>, las
	alarmas usan la palabra <literal>alarm</literal>.</para></listitem>
	<listitem><para>No puede especificarse el atributo
	<literal>path</literal>, dado que las alarmas se copian siempre a un
	directorio especial (que, hasta cierto punto, puede personalizar el
	administrador).</para></listitem>
	<listitem><para>Las alarmas añaden una construcción optativa llamada
	<literal>uses</literal>, para especificar
	<emphasis>dependencias</emphasis> de la alarma. Los ficheros
	especificados aquí, que se instalan siempre que se instala la alarma,
	son normalmente ficheros de configuración de las alarmas. Por
	supuesto, estos ficheros pueden declararse y copiarse aparte, pero se
	corre el peligro de copiar las alarmas y no los ficheros de
	configuración.</para></listitem>
	<listitem><para>Para no mezclar los ficheros de alarmas con los demás
	objetos, por defecto las alarmas se buscan en
	<literal>$picasrc/alarms</literal> en vez de a partir de
	<literal>$picasrc</literal>.</para></listitem>
      </itemizedlist>

      <para>Con todo esto, tenemos que un ejemplo de declaración de alarma
      podría ser:</para>

      <example>
	<title>Ejemplo de declaración de alarma</title>

	<programlisting>
alarm alarmaPrueba {
   source   = prueba;
   priority = Urgent;
   vars {
      mivariable = mivalor;
      limite     = 80;
      servidor   = central;
      modo       = simple;
      rutabin    = /usr/local/bin;
   }
   uses {
      file alarmaPruebaConfig {
         source = alarms/config/prueba.conf;
	 path   = &lt;# $picaalarms #&gt;/config/prueba.conf;
      }
   }
}
	</programlisting>
      </example>
    </sect2>

    <sect2>
      <title>Componentes de PIFIA</title>

      <para>Actualmente podemos decir que PIFIA se compone de:</para>

      <itemizedlist>
	<listitem><para>Un módulo de Perl con definiciones útiles para escribir
	alarmas, como persistencia en forma de extensión de la
	sintaxis.</para></listitem>
	<listitem><para>Tres programas para gestionar las alarmas de forma local
	(aunque están pensados para instalarse y ejecutarse remotamente con
	PICA).</para></listitem>
	<listitem><para>Un programa que ejecuta periódicamente todas las alarmas
	que haya instaladas en un momento dado.</para></listitem>
	<listitem><para>Un fichero para el <application>cron</application>, que
	ejecuta las alarmas en los intervalos apropiados.</para></listitem>
	<listitem><para>Un fichero para incluir en
	<filename>objects.conf</filename> que define todos los ficheros
	necesarios para ejecutar las alarmas. Estos ficheros deben copiarse a
	cualquier máquina donde queramos ejecutarlas.</para></listitem>
      </itemizedlist>
    </sect2>
  </sect1>

  <sect1>
    <title>El PPP (Perl PreProcessor)</title>

    <para>Como dijimos al principio, todos los ficheros de configuración y de
    distribución de PICA se preprocesan antes de pasar por el analizador
    sintáctico. Este componente es uno de los puntos más importantes de PICA,
    porque es el que le da gran parte de su flexibilidad. Es fácil de usar
    y entender y da unas posibilidades a la hora de tratar los ficheros a
    distribuir que, al menos de forma tan sencilla, no hemos encontrado en
    ninguna otra herramienta.</para>

    <para>El preprocesador es una función escrita en Perl que hace las
    sustituciones necesarias en el fichero, generando uno nuevo ya
    preprocesado. Es muy parecido al preprocesador de C, pero con algunas
    diferencias importantes:</para>

    <itemizedlist>
      <listitem><para>Hay dos primitivas para incluir programas en Perl, para
      generar dinámicamente partes de los ficheros.</para></listitem>
      <listitem><para>Las expresiones que ponemos en las condiciones y
      similares son Perl puro (que se <function>eval</function>úan), que pueden
      consultar el espacio de nombres de la aplicación para consultar ciertas
      variables del estado interno, como el fichero o la máquina actual que se
      están procesando, etc.</para></listitem>
    </itemizedlist>

    <para>La lista completa de opciones que nos da el preprocesador es:</para>

    <itemizedlist>
      <listitem><para>Una directiva <literal>#if/#elsif/#else/#fi</literal>
      para condiciones simples. En estas condiciones podemos poner expresiones
      genéricas en Perl.</para></listitem>
      <listitem><para>Una directiva <literal>#include</literal> para incluir
      ficheros (que serán procesados recursivamente), como en el caso del
      C.</para></listitem>
      <listitem><para>Una directiva <literal>#perl/#lrep</literal> para
      generar dinámicamente partes del fichero a distribuir. Lo que se
      <emphasis>devuelva</emphasis> en el entorno
      <literal>#perl/#lrep</literal> quedará en el fichero final a
      copiar.</para></listitem>
      <listitem><para>Una directiva <literal>&lt;#/#&gt;</literal> que
      funciona igual que la anterior, pero es una versión reducida, más
      cómoda, para usar en una sola línea.</para></listitem>
    </itemizedlist>

    <para>Veamos un ejemplo del preprocesador de PICA en acción, con uno de los
    ficheros de ejemplo que vienen en la distribución oficial:</para>

    <example>
    <title>Ejemplo de fichero de distribución de PICA</title>

    <programlisting>
Well, this is just a test file to see if it worked...

The value of the (local) variable myvar is '&lt;# $myvar #&gt;'
The value of the (local) variable mythirdvar is '&lt;# $mythirdvar #&gt;'


$myvar is &lt;# ($myvar lt $mythirdvar)?'less':'greater' #&gt; than
$mythirdvar...

The crypt'ed version of $mythirdvar is '&lt;# crypt $mythirdvar,
'aa' #&gt;'.


Now, a little list from 0 to &lt;# $limit #&gt;:
#perl
my @result;
for (my $i = 0; $i &lt; $limit; ++$i) {
        push @result, "$i\n";
}
@result;
#lrep
    </programlisting>
    </example>

    <para>Suponiendo una definición como la siguiente:</para>

    <example>
    <title>Ejemplo de definición del fichero pica-rules en <filename>objects.conf</filename></title>

    <programlisting>
file pica-rules {
    path = '&lt;#$picaroot#&gt;/rules';	  # Esto también se
                                          # preprocesará
    source = 'pica-rules';

    vars {
       myvar         = 'foo';
       limit         = '2';
       mythirdvar    = 'enough';
    }
}
    </programlisting>
    </example>

    <para>el resultado del fichero, ya preprocesado, sería:</para>

    <example>
    <title>Fichero preprocesado por PPP</title>

    <literallayout>
Well, this is just a test file to see if it worked...

The value of the (local) variable myvar is 'foo'
The value of the (local) variable mythirdvar is 'enough'


$myvar is greater than $mythirdvar...

The crypt'ed version of $mythirdvar is 'aaVxUBNI9d3lI'.


Now, a little list from 0 to 2:
0
1
    </literallayout>
    </example>

    <para>Esta versión es, naturalmente, la que se instalaría en las
    máquinas. Nótese además que el fichero de configuración de definición de
    objetos (<filename>objects.conf</filename>) y los ficheros de distribución
    vuelven a leerse y preprocesarse por cada máquina, así que podemos hacer
    que éstos dependan del objetivo donde se instalarán (ver ejemplo "Creación
    de varios ficheros a partir de un solo fuente" en el siguiente
    apartado).</para>
  </sect1>

  <sect1>
    <title>Ejemplos de usos reales de PICA</title>

    <para>En este apartado se dan ejemplos reales de usos que le hemos dado a
    PICA, que muestran diversas características del programa.</para>

    <sect2>
      <title>Distribución de claves RSA</title>

      <para>Para no estar continuamente escribiendo claves a la hora de acceder
      a los servidores por SSH, hemos distribuido nuestras claves públicas en
      varios servidores y activado los agentes RSA. La propia distribución de
      las claves puede hacerse de forma automática con PICA. A continuación
      presentamos el extracto de <filename>objects.conf</filename> donde se
      definen los ficheros a distribuir, y su contenido.</para>

      <example>
        <title>Distribución de claves RSA: extracto de <filename>objects.conf</filename></title>

        <programlisting>
group RSAAuth {
    # Fichero de autorización de SSHv2
    file ssh_auth {
         path = '/root/.ssh2/authorization';
         source = "SSH/authorization.cfg";
    }
    file sysadm1.pub {
         path = '/root/.ssh2/sysadm1.pub';
         source = "SSH/sysadm1.pub";
    }
    file sysadm2.pub {
         path = '/root/.ssh2/sysadm2.pub';
         source = "SSH/sysadm2.pub";
    }
    # ...
    # Resto de las definiciones de ficheros de clave pública
}
        </programlisting>
      </example>

      <para>Por supuesto, podríamos haber generado dinámicamente las entradas
      para los ficheros de clave pública, pero no creemos que valga la pena, por
      seguridad y porque probablemente no serán muchas.</para>

      <example>
        <title>Distribución de claves RSA: fichero <filename>authorization.cfg</filename></title>

        <programlisting>
#perl
my @return;
# Obtenemos los ficheros de clave leyendo los miembros del grupo
# SSHAuth, pero saltándonos el fichero 'ssh_auth'
my @keys=grep(/\.pub$/,members('SSHAuth'));
foreach my $key (@keys) {
  push @return,"Key $key\n";
}
# Devolvemos la lista (se imprimirá en la versión final del
# fichero)
@return;
#lrep
        </programlisting>
      </example>

      <para>Después de preprocesarse, el fichero contendrá los nombres de los
      ficheros &laquo;lógicos&raquo; (es decir, lo que va después de
      <function>file</function>) que terminen en <literal>.pub</literal>, uno
      por línea, precedidos de <literal>Key</literal>, es decir, algo como
      esto:</para>

      <example>
        <title>Distribución de claves RSA: ejemplo de fichero
        <filename>authorization</filename> creado automáticamente</title>

        <literallayout>
Key sysadm1.pub
Key sysadm2.pub
...
        </literallayout>
      </example>
    </sect2>

    <sect2>
      <title>Creación de varios ficheros a partir de un solo fuente</title>

      <para>Otra de las posibilidades que nos brinca PICA es concentrar en un
      solo fuente todas las variaciones necesarias de un fichero, mediante
      condicionales. Por ejemplo, podemos querer instalar en la misma máquina
      dos ficheros iguales a partir del mismo fuente. Este caso se nos
      dio en los servidores primarios de nombres, en los que además queríamos
      guardar ficheros de ejemplo de los secundarios para publicarlos en web.
      Para ello, no nos hizo falta nada especial: pudimos aprovechar el mismo
      fuente para ambas versiones.</para>

      <example>
	<title>Declaración de los servidores DNS</title>

	<programlisting>
hostgroup dnsservers {
    members { fobos, deimos, mercurio, ulpnet, ulpnet2 }
}
hostgroup dnsmaster {
    members { ulpnet, ulpnet2 }
}
hostgroup doc {
    members { ulpnet, ulpnet2 }
}
	</programlisting>
      </example>

      <para>Como vemos, tenemos declarados los grupos de máquinas que dan
      servicio DNS, los que son servidores principales, y los que hacen de
      servidor de documentación (que coinciden con los servidores principales
      de nombres). Los objetos se declararon de la siguiente manera:</para>

      <example>
	<title>Declaración de los objetos a instalar</title>

	<programlisting>
#if (ingroup('dnsservers'))
group DNS {
    file named.conf {
         path = '/etc/named.conf';
         source = "DNS/named_conf.cfg";
    }

    ## Documentación del servicio
#  if (ingroup('doc'))
    # ...
    file named.conf.sample {
       path = '&lt;#$docdir#&gt;/Servicios/DNS/named.conf.sample';
       source = 'DNS/named_conf.cfg';
    }
#  fi
}
#fi
	</programlisting>
      </example>

      <para>De esta forma, sabemos que ambos ficheros se van a sacar del mismo
      fuente (<filename>DNS/named_conf.cfg</filename>), <emphasis>y</emphasis>
      que los ficheros de ejemplo siempre terminan en
      <literal>.sample</literal>. Con esta información tenemos suficiente para
      poder distinguir con el preprocesador. El contenido del fichero
      <filename>named.conf.cfg</filename> será algo como:</para>

      <example>
	<title>Contenido parcial del fichero <filename>named.conf.cfg</filename></title>

	<programlisting>
# ...
zone "ulpgc.es" {
#if ((ingroup('dnsmaster')) && ($picaobject !~ /\.sample$/))
   type master;
   file "mydb.db";
   also-notify {
      # ...
   };
#else
   type slave;
   file "mydb.db.bak";
   masters {
      # ...
   };
#fi
};
# ...
	</programlisting>
      </example>

      <para>Así, cada vez que se vaya a instalar cualquier fichero en los
      servidores de nombre primarios, se comprobará el nombre del fichero (el
      nombre del objeto en el fichero de configuración, no del fuente). Si
      termina en <literal>.sample</literal>, el contenido será el de un
      servidor secundario de DNS; si no, será la configuración de un DNS
      primario. Si la máquina donde va a instalarse es un secundario, no hay
      posible ambigüedad, siempre se instala la versión de servidor
      secundario.</para>
    </sect2>
  </sect1>

  <sect1>
    <title>Conclusiones</title>

    <para>PICA es una herramienta sencilla, muy fácil de aprender y sin
    grandes pretensiones. Consideramos que, excepto en instalaciones muy
    grandes, no vale la pena aprender complicados conceptos y nuevos lenguajes
    para resolver problemas; PICA resuelve problemas sin exigir que el
    administrador aprenda nada que no le sea familiar.</para>
  </sect1>

  <sect1>
    <title>Licencia</title>

    <para>Copyright Esteban Manchado Velázquez
    (<email>zoso@demiurgo.org</email>) y Miguel Ángel Armas del Río
    (<email>kuko@ulpgc.es</email>). Se otorga permiso para copiar, distribuir
    y/o modificar este documento bajo los términos de la Licencia de
    Documentación Libre GNU Versión 1.1, publicada por la Free Software
    Foundation.  Puede consultar una copia de la licencia
    en: http://www.gnu.org/copyleft/fdl.html</para>
  </sect1>
</article>
