26 diciembre 2013

Documentando el código con Sphinx

A la hora de escribir código que vaya a ser usado por otros resulta crítico documentarlo adecuadamente. Esto ayudará a los usuarios de nuestro código a sacarle el máximo provecho y a comprender las opciones de diseño adoptadas.

Sin embargo, documentar código puede ser una tarea tediosa. Ya es difícil que los programadores comenten adecuadamente el código fuente como para encima exigirles que mantengan actualizado un documento aparte con las explicaciones de uso de funciones y objetos. Por eso, hay muchas herramientas que permiten generar el código a partir de los comentarios plasmados en el mismo código fuente. De esta manera los programadores sólo tienen que plasmar la información en un sitio (el código fuente) lo que facilita el mantenerla actualizada.

En el mundo Python, una de las herramientas más usadas para estos fines es Sphinx, la cual genera una documentación con un formato similar a la de la documentación de Python (no en vano esta también ha sido generada con Sphinx). Para generar la documentación, Sphinx inspecciona el código fuente del directorio que le digamos y detecta todos los paquetes, módulos, clases y funciones recogidos allí, y a cada uno de ellos le asocia sus correspondientes docstrings.

Un docstring es un comentario que se coloca en la primera línea del módulo, función o clase que comenta. Se encierra entre dos grupos de tres comillas dobles ("""...""") y a diferencia de los comentarios "de programador" (iniciados con una almohadilla #), que sencillamente son ignorados por el intérprete de Python, los docstrings se guardan en el atributo __doc__ de aquello que comentan (hay que recordar que en Python hasta las funciones son objetos susceptibles de tener sus propios atributos). Mientras que los comentarios de programador están pensados para ser leídos por aquellos que vayan a modificar directamente el código, los docstring están más orientados a aquellos que vayan a hacer uso del código. Por eso, mientras los comentarios de programador se enfocan a explicar por qué se ha programado el código de una determinada manera, los docstring se suelen utilizar para explicar cómo utilizar cada módulo, función o clase. La PEP-8 establece las buenas prácticas de escritura de código en Python y redirige a la PEP-257 para el caso concreto de los docstrings.

En realidad, no hay una única manera de escribir docstrings y aún siguiendo las buenas prácticas el tema está muy abierto. Google recomienda un formato para los docstrings que prima la claridad en su lectura directa, sin embargo si queremos generar documentación de manera automática mediante Sphinx deberemos seguir un formato que quizás no es tan claro a primera vista, pero que utiliza las etiquetas que el programa identificará para construir la documentación en base a los docstrings.

Pero empecemos por el principio instalando primero Sphinx. El código fuente del programa se puede obtener de su repositorio en Bitbucket. Desde allí se puede bajar el programa en un único paquete comprimido. En Ubuntu se encuentra en los repositorios oficiales con el nombre de "python-sphinx", por lo que bastará con un simple:

dante@Camelot:~$ sudo aptitude install python-sphinx


En Windows, lo mejor es usar pip o easy_install (incluido en setuptools), dado que Sphinx se encuentra en el repositorio oficial de Pypi.

Una vez instalado, Sphinx se usa con unos pocos comandos. Para empezar debemos generar la carpeta de trabajo de Sphinx. Supongamos que nuestros ficheros de código fuente están en la carpeta /pyalgorithm , allí he volcado una librería denominada PyAlgorithm que está desarrollando un amigo, de manera que el contenido de la carpeta es el siguiente:

dante@Camelot:~/pyalgorithm$ ls __init__.py  __init__.pyc  __pycache__  checkers  exceptions.py  exceptions.pyc  multiprocessing  stats  time

Todos los elementos, menos los que tienen extensión, son directorios con código fuente.

Desde allí lanzaremos el asistente para la configuración inicial de Sphinx para nuestro proyecto, sphinx-quickstart:

dante@Camelot:~/pyalgorithm$ sphinx-quickstart Welcome to the Sphinx 1.1.3 quickstart utility. Please enter values for the following settings (just press Enter to accept a default value, if one is given in brackets). Enter the root path for documentation. > Root path for the documentation [.]: docs                                                                                                                                                                                                                   You have two options for placing the build directory for Sphinx output.                                                                                                                                           Either, you use a directory "_build" within the root path, or you separate                                                                                                                                       "source" and "build" directories within the root path.                                                                                                                                                           > Separate source and build directories (y/N) [n]:                                                                                                                                                                                                                                                                                                                                                                                 Inside the root directory, two more directories will be created; "_templates"                                                                                                                                     for custom HTML templates and "_static" for custom stylesheets and other static                                                                                                                                   files. You can enter another prefix (such as ".") to replace the underscore.                                                                                                                                     > Name prefix for templates and static dir [_]:                                                                                                                                                                                                                                                                                                                                                                                     The project name will occur in several places in the built documentation.                                                                                                                                         > Project name: PyAlgorithm                                                                                                                                                                                   > Author name(s): Nobody                                                                                                                                                                                     Sphinx has the notion of a "version" and a "release" for the software. Each version can have multiple releases. For example, for Python the version is something like 2.5 or 3.0, while the release is something like 2.5.1 or 3.0a1.  If you don't need this dual structure, just set both to the same value. > Project version: 1 > Project release [1]: The file name suffix for source files. Commonly, this is either ".txt" or ".rst".  Only files with this suffix are considered documents. > Source file suffix [.rst]: One document is special in that it is considered the top node of the "contents tree", that is, it is the root of the hierarchical structure of the documents. Normally, this is "index", but if your "index" document is a custom template, you can also set this to another filename. > Name of your master document (without suffix) [index]: Sphinx can also add configuration for epub output: > Do you want to use the epub builder (y/N) [n]: Please indicate if you want to use one of the following Sphinx extensions: > autodoc: automatically insert docstrings from modules (y/N) [n]: y > doctest: automatically test code snippets in doctest blocks (y/N) [n]: > intersphinx: link between Sphinx documentation of different projects (y/N) [n]: > todo: write "todo" entries that can be shown or hidden on build (y/N) [n]: > coverage: checks for documentation coverage (y/N) [n]: > pngmath: include math, rendered as PNG images (y/N) [n]: > mathjax: include math, rendered in the browser by MathJax (y/N) [n]: > ifconfig: conditional inclusion of content based on config values (y/N) [n]: > viewcode: include links to the source code of documented Python objects (y/N) [n]: y A Makefile and a Windows command file can be generated for you so that you only have to run e.g. `make html' instead of invoking sphinx-build directly. > Create Makefile? (Y/n) [y]: > Create Windows command file? (Y/n) [y]: Creating file docs/conf.py. Creating file docs/index.rst. Creating file docs/Makefile. Creating file docs/make.bat. Finished: An initial directory structure has been created. You should now populate your master file docs/index.rst and create other documentation source files. Use the Makefile to build the docs, like so:    make builder where "builder" is one of the supported builders, e.g. html, latex or linkcheck. dante@Camelot:~/pyalgorithm$


Como se puede ver el asistente es muy sencillo y la mayor parte de las veces nos basta con la opción por defecto con un par de notables excepciones:

  1. Si no queremos que nuestros ficheros de documentación se mezclen con los del código fuente debemos responder a la pregunta "Root path for the documentation [.]:" con el directorio que queremos que se cree, dentro de /pyalgorithm, para ir colocando los ficheros de trabajo de Sphinx así como los de documentación generado.
  2. Por otro lado, hay que estar atento para responder "Yes" a la pregunta: "autodoc: automatically insert docstrings from modules (y/N) [n]:", ya que autodoc es precisamente la extensión de Sphinx que analiza los docstrings para generar la documentación.
Vemos que el asistente ha creado el directorio docs:

dante@Camelot:~/source$ ls __init__.py  __init__.pyc  __pycache__  checkers  docs  exceptions.py  exceptions.pyc  multiprocessing  stats  time

Así como 4 ficheros dentro de él:
  • conf.py: Es un fichero de Python donde se recoge la configuración de Sphinx. Si en algún momento quisieramos cambiar alguna de las opciones elegidas con sphinx-quickstart sería en este fichero donde la cambiaríamos. Por ejemplo, si quisiéramos cambiar los números de versión de la configuración lo haríamos cambiando las variables version y release de ese fichero. En realidad, lo único que es indispensable modificar en ese fichero es una línea que hay que descomentar al principio y que dice: "sys.path.insert(0, os.path.abspath('.'))". Esa línea sirve para que Sphinx sepa encontrar los elementos de nuestro código fuente. Tenemos dos opciones: poner la ruta a nuestro código fuente relativa al directorio de Sphinxs (en nuestro ejemplo docs/) o poner la ruta absoluta. En el primer caso y partiendo de que, en nuestro ejemplo, el archivo se encuentra en /pyalgorithm/docs/conf.py habría que poner: sys.path.insert(0, os.path.abspath('../../')). En caso de que queramos usar la ruta absoluta habría que quitar las parte del abspath() y poner directamente la ruta: sys.path.insert(0, "ruta hasta conf.py").
  • Makefile: A la hora de generar la documentación Sphinx usa make. Este fichero Makefile cuenta con lo necesario para renderizar la documentación en múltiples formatos: html, pdf, latex, epub, etc. De esta manera, para generar la documentación en formato html basta con hacer: make html. La documentación generada se deposita en el directorio build, dentro del de Sphinx.
  • make.bat: Ejecutable de make para los usuarios de Windows.
  • index.rst: Plantilla de la página de inicio de la documentación generada. Está estructurada en formato reStructuredText. Este formato permite crear plantillas que le sirven a Sphinx para estructurar la información extraída de los ficheros de código fuente.
Si llegados a este punto ejecutamos "make html" veremos que se generan ficheros html, pero si abrimos el de index veremos que está vacío. Esto es así porque Sphinx espera encontrar un fichero .rst por cada uno de los paquetes que queramos documentar. Podemos crearlos a mano, pero es más cómodo utilizar el comando sphinx-apidoc, el cual examina el directorio del código fuente y genera un fichero .rst por cada uno de los paquetes que detecte. Su uso es muy sencillo, en nuestro caso bastaría con hacer:

dante@Camelot:~/pyalgorithm$ sphinx-apidoc -o docs .

En la opción -o ponemos el directorio donde queremos que se creen los fichero .rst y en el siguiente parámetro el directorio desde el que queremos que sphinx-apidoc empiece a buscar. En nuestro ejemplo se generarían los siguientes ficheros:
dante@Camelot:~/pyalgorithm$ ls *.rst index.rst pyalgorithm.checkers.rst pyalgorithm.rst pyalgorithm.time.rst modules.rst  pyalgorithm.multiprocessing.rst  pyalgorithm.stats.rst
Con estos ficheros podríamos hacer "make html" y veríamos que se generarían bastantes ficheros html (en realidad uno por fichero .rst). Sin embargo, el fichero de index.html seguiría mostrando una página vacía. Eso se debe a que tenemos que configurarla para que incluya enlaces al resto de las páginas. En nuestro caso la documentación hace referencia a una librería cuya raiz es pyalgorithm, por eso en index.rst debemos hacer incluir la referencia a él:

Welcome to PyAlgorithm's documentation!
=======================================
Contents:
.. toctree::
   :maxdepth: 3
 
   pyalgorithm

Al encontrar esa referencia, Sphinx buscará el fichero pyalgorithm.rst y plasmará su contenido en index.html, así como las referencias que se encuentren a su vez en pyalgorithm.rst y luego recursivamente en este, así hasta alcanzar la "profundidad" máxima definida en el parámetro ":maxdepth". Siguiendo nuestro ejemplo, ya hemos visto el contenido de index.rst, si definimos un maxdepth de 3 en index.rst, siendo el contenido de pyalgorithm.rst:

pyalgorithm package
===================
Subpackages
-----------
.. toctree::
    pyalgorithm.checkers
    pyalgorithm.multiprocessing
    pyalgorithm.stats
    pyalgorithm.time
pyalgorithm.exceptions module
-----------------------------
.. automodule:: pyalgorithm.exceptions
    :members:
    :undoc-members:
    :show-inheritance:

el resultado sería:



Mientras que si lo fijásemos en 4 acudiría a examinar cada uno de los .rst que cuelgan de pyalgorithm.rst y el resultado sería:



Podemos fijar el nivel que queramos. Una vez alcanzado el nivel máximo hay que pinchar en cada enlace para ver los subniveles adicionales que haya agregados en él.

Los ficheros .rst que se refieren a los paquetes con módulos cuentan con una serie de tags de Sphinx a los que hay que prestar especial atención, veamos un ejemplo:

pyalgorithm.checkers package
============================
pyalgorithm.checkers.input_decorators module
--------------------------------------------
.. automodule:: pyalgorithm.checkers.input_decorators
    :members:
    :undoc-members:
    :show-inheritance:

Este fichero .rst, generado por sphinx-apidoc, hace referencia a un paquete ("pyalgorithm.checkers") en el que se han detectado módulos (en este caso "input_decorators"). El fichero .rst explica cómo generar la documentación asociada a dicho módulo. El tag automodule pertenece a las etiquetas que utiliza la extensión autodoc de Sphinx (junto con las etiquetas autoclass y autofunction) y le dice a Sphinx que documente el módulo cogiendo el docstring que haya en el fichero de código fuente del módulo a comienzo del todo. Las etiquetas autoclass y autofunction hacen lo mismo pero a nivel de clase y función respectivamente. La etiqueta members hace que autodoc incluya en la documentación a los miembros "publicos" del elemento, es decir aquellos atributos cuyo nombre no vaya precedido de un guión bajo ("_"), mientras que "undoc-members" hace que se incluya en la documentación aquellos elementos que carezcan de docstring poniendo al menos su declaración. Si quisiéramos mostrar los elementos privados (los que empiecen por "_" o "__") deberíamos utilizar la etiqueta "private-members". Si sólo queremos mostrar los miembros públicos nos encontraremos con que en las clases no se muestran los constructores, para que aparezcan en la documentación hay que incluir la etiqueta ":special-members: __init__" junto a la de "members". En cuanto a la etiqueta "show-inheritance" lo que hace es mostrar el listado de clases base de la que hereda la documentada situando dicho listado debajo de la declaración de la clase. Estas son las etiquetas que incluye sphinx-apidoc, pero hay muchas más. Somos libres de incluir más etiquetas y opciones de formato para hacer que nuestra documentación plasme la información que deseamos en el formato que más nos guste. También podemos cambiar el texto de los ficheros .rst dado que estos son meras plantillas, lo que pongamos en ellas se añadirá a lo que genere automáticamente Sphinx al hacer el "make".

Las etiquetas también se pueden incluir a los docstrings para ayudar a Sphinx a distinguir a qué hace referencia cada elemento del texto. Veamos cómo se documentaría una función:

 def apply_async(self, func, args):
        """Insert a function and its arguments in process pool.
     
        Input is inserted in queues using a round-robin fashion. Every job is
        identified by and index that is returned by function. Not all parameters
        of original multiprocessing.Pool.apply_aync are implemented so far.
     
        :param func: Function to process.
        :type func: Callable.
        :param args: Arguments for the function to process.
        :type args: Tuple.
        :returns: Assigned job id.
        :rtype: Int.
        """

Las etiquetas de Sphinx utilizadas en el ejemplo anterior son:
  • param : Identifica un argumento de la declaración de la función.
  • type : Tipo esperado del argumento.
  • returns: Lo que devuelve la función.
  • rtype: El tipo esperado de lo que devuelve la función.
El docstring anterior se renderizaría de la siguiente manera:




No quiero acabar sin comentar un problema con el que me he encontrado cuando se le pide a Sphinx que actúe sobre un directorio con carpetas que tengan scripts de Unittest. En esos casos he tenido que mover la carpeta fuera del ámbito que examina Sphinx para permitir que este funcionase sin problemas al hacer el "make html". Esto no es sino un workaround bastante tosco, si alguien encuentra una solución más elegante estaré encantado de escucharla.



11 octubre 2013

PyConEs 2013

Las PyCon son ciclos de conferencias en las que los amantes del lenguaje Python pueden reunirse y compartir su pasión. A lo largo de los años se han celebrado en multitud de países: Estados Unidos, Francia, Canadá, Australia, China y un largo etcétera... con una notable salvedad: nunca se había celebrado una en España.

Afortunadamente, la asociación de Python España se ha puesto manos a la obra para organizar una y lo cierto es que parece que con notable éxito. Se denominará PyConEs y tendrá lugar en Madrid el 23 y 24 de Noviembre. Los chicos de Python España han conseguido involucrar a una extensa lista de patrocinadores. Algunos gigantes como Produban (Grupo Santander) o Telefónica I+D son agradables sorpresas en el apoyo a Python.

Las conferencias se estructurarán en tres ejes temáticos: básico, avanzado y científico. Y el contenido de las mismas es de lo más variopinto aunque todas tremendamente interesantes. Planificar una "ruta" de conferencias dentro de la agenda ha sido bastante difícil dado que no se dejaban de repetir las situaciones en las que me hubiera gustado poder ser capaz de dividirme para acudir a las tres conferencias al mismo tiempo. Esperemos que, como en otras PyCon, cuelguen los videos de las conferencias para que podamos ver a posteriori aquellas a las que no hayamos podido asistir.

A quién se le hayan puesto los dientes largos he de decirle que le comprendo pero que, sintiéndolo mucho, las entradas ya están agotadas. Se agotaron en Septiembre y aunque volvieron a sacar más el 1 de Octubre se volvieron a acabar en pocas horas. Todo apunta que los afortunados que nos adelantamos a comprar las entradas nos vamos a encontrar con un estupendo ambiente. Y los que se hayan quedado sin entradas siempre pueden pasar por este blog, donde algo contaré de cómo transcurre todo para ir poniendo los dientes largos :-P

23 agosto 2013

Creación de laboratorios virtuales con GNS3

La necesidad de crear laboratorios virtuales es común a todos los ingenieros de seguridad que quieran experimentar técnicas y configuraciones nuevas. De hecho, ya exploramos la posibilidad de crear este tipo de laboratorios utilizando Netkit (artículo 1 y artículo 2).

Netkit es tremendamente potente, pero cuenta con una serie de limitaciones a tener en cuenta:

  • Su configuración es compleja.
  • Sólo hay versión para Linux (para los que estamos saltando continuamente de Linux a Windows, eso es un problema).
  • Sólo emula máquinas Debian.
Sin embargo, hace poco comencé a trastear con GNS3 y he de reconocer que los resultados han sido más que satisfactorios:
  • Emula equipos Cisco y Juniper (este último mediante Olive, así que sólo de manera parcial).
  • Permite incluir en los laboratorios máquinas virtuales preexistentes de VirtualBox y QEmu.
  • Cuenta con versiones para Windows, Linux y Mac OS.
  • Su interfaz gráfica es bastante intuitiva.
GNS3 es "open source" y se puede descargar gratuitamente. Su modelo de negocio se basa en ofrecer anuncios de cursos para la preparación de las certificaciones CCNA, CCNP, etc. Como GNS3 también se puede utilizar para preparar esas certificaciones dicha publicidad está dentro de contexto y como los anuncios se limitan a una pantalla emergente al arrancar el programa (que se puede cerrar sin problemas) tampoco es que moleste en absoluto.

Cuando abrimos GNS3 vemos un interfaz muy visual. La pantalla principal está ocupada principalmente por la zona de diseño, acompañada por una ventana de consola para ver el logging de la aplicación, y dos ventanas a la derecha, una con el listado de elementos que iremos añadiendo a la zona de diseño y otra con las capturas de tráfico que tengamos activas. Gracias a las ventanas de la derecha se pueden sacar capturas de tráfico de cualquiera de los puertos del laboratorio y visualizarlas en wireshark con sólo un par de clicks.



A la izquierda se pueden ver los distintos elementos que podemos arrastrar a la zona de diseño. Al principio veremos que la mayor parte de los iconos referentes a routers están sombreados y no se pueden incorporar al esquema. Esto es así porque cada uno de esos iconos representa un modelo concreto de equipo y para poder usarlo hay que asociar una imagen de firmware a cada uno de ellos (las famosas IOS de Cisco). GNS3 no trae esos firmware ya que son propietarios de Cisco y esta cobra por ellos. Sólo podremos cargar esos firmware si trabajamos en una empresa que sea partner de Cisco y tenga acceso a ellos o bien si los hemos conseguido por otros medios (Internet, amigos, etc. allá cada uno con su conciencia).

Supongamos que tenemos IOS compatibles con cada uno de los modelos que GNS3 puede emular, para asociarlos a los diferentes dispositivos deberemos acceder a: "Edit -> IOS Images and Hipervisors" o simplemente pulsar Control+Shif+I. 



Allí nos limitaremos a elegir una plataforma, un modelo concreto y cargarle el fichero .bin o .image de la IOS que tengamos para él. Por lo que he visto en las pruebas que he realizado no todas las IOS parecen funcionar. Lo mejor es usar el botón de "Test Settings" tras seleccionar una imagen, se abrirá una ventana de consola que intentará poner a funcionar la imagen. Si la imagen se puede ejecutar bien acabaremos viendo un prompt de router en la ventana. Sin embargo, si el tema se atasca y empiezan a salir mensajes de error entonces significa que la imagen es compatible con GNS3 y que tenemos que probar con otra IOS. Cuando por fin demos con una IOS que valga pulsamos el botón de "Save" y listo, a partir de ahí podremos incorporar ese tipo de router a nuestros diseños.

GNS es capaz de emular routers, pero no puede simular la arquitectura utilizadas en los switches por lo que en teoría no podríamos practicar esa parte con GNS2 si estuviéramos preparando alguna certificación de Cisco o simplemente aprendiendo a manejar sus equipos. Sin embargo, hay un truco que puede servir para solventar este problema, se trata de emular un 3600 con una IOS de 3640 y una tarjeta NM-16ESW. Esta tarjeta dota de capacidades de switching (limitadas eso sí) al router en el que se integre.

Para definir las tarjetas con las que irá equipado cada router de nuestro diseño (y por tanto los puertos con los que contará para comunicarse con el resto de los elementos), arrastraremos el equipo a la zona de diseño y una vez allí lo seleccionaremos con el botón derecho y le daremos a "Configure". En la ventana que saldrá podremos definir determinadas condiciones operativas del equipo: su RAM, si tiene tarjeta PCMCIA, su confreg, etc. Pero la pestaña que nos permitirá definir que tarjetas llevará es la que se denomina "Slots". Una vez que hayamos dicho con qué tarjetas queremos dotar a cada uno de los slots del equipo pulsaremos "Apply".

Para interconectar los diferentes elementos que añadamos a la zona de diseño pulsaremos en el icono de la izquierda de más abajo (el que parece un conector RJ45). Al hacerlo se nos dará a elegir varios modos automáticos de interconexión, yo le doy siempre a "Manual" que me parece el más intuitivo. Tras eso, el cursor pasará a una cruz con la que no tendremos más que señalar los dos equipos que queremos interconectar entre sí y los puertos que queremos utilizar en cada extremo.

Una vez hecha nuestra topología de laboratorio, puede ser que queramos darle acceso a Internet. Es ese caso tendremos que usar el objeto "Cloud", que está junto al de "Virtualbox guest" y "Qemu guest". Para hacerlo funcionar seguí un excelente artículo de otro usuario de Blogger. Básicamente la técnica consiste en crear un interfaz de loopback en nuestro ordenador, dar permisos para que el mismo utilice nuestra tarjeta de red para conectarse a Internet y luego asociar este interfaz de loopback al objeto "Cloud" dentro de GNS3.

En Windows 7, los interfaces de loopback se pueden crear en la ventana de "Administrador de dispositivos" del "Panel de Control", utilizando la opción "Acción -> Agregar hardware heredado". Allí, tras darle a "Siguiente", cuando nos den a elegir optaremos por seleccionar el dispositivo manualmente de la lista. Después iremos a la categoría de "Adaptadores de red" y elegiremos la marca "Microsoft". En la lista que nos aparezca encontraremos la opción de "Microsoft loopback adapter " o "Adaptador de bucle invertido" según nuestra traducción. Con esto ya tendremos instalado el adaptador de loopback como una tarjeta de red más de nuestro ordenador.

Una vez que contemos con un interfaz de loopback, lo siguiente es permitirle usar nuestra tarjeta de red para acceder a Internet. En " Panel de control -> Redes e Internet -> Centro de redes y recursos compartidos" seleccionaremos la tarejta de red que usemos habitualmente para salir a Internet y, en sus "Propiedades" accederemos a la pestaña de "Uso compartido". Allí marcaremos la opción "Permitir que los usuarios de otras redes se conecten a través de la conexión a Internet de este equipo" y en la lista de "Conexión de red doméstica" seleccionaremos nuestro adaptador de loopback.

Y ya sólo queda el último paso, asociar el objeto "Cloud" del GNS3 al interfaz de loopback. Para ello pulsaremos con el botón derecho en el objeto "Cloud" de la zona de diseño y seleccionaremos "Configure". Allí veremos una ventana como esta:


En ella, en la pestaña "NIO Ethernet" seleccionaremos el interfaz de loopback y pulsaremos en "Add" y luego en "Apply".

El interfaz de loopback adquirirá una dirección privada que podremos averiguar en la consola con un simple "ipconfig":



Esa dirección IP es la que tendrá el objeto "Cloud" y será contra la que tendremos que dirigir el tráfico que queramos que salga de nuestro laboratorio hacia Internet. Conceptualmente será como la IP del PoP de nuestro ISP. Igual que pasaría en ese caso, hay que tener en cuenta que nuestro ordenador, como nuestro ISP, no conoce el direccionamiento interno utilizado en nuestro laboratorio. Para asegurar que las respuestas son capaces de volver a la red virtual del laboratorio hay dos opciones:

  • Poner una ruta en el ordenador que apunte hacia las redes virtuales, usando como gateway la IP del router virtual que se enfrente con la IP de la Cloud.
  • Hacer PAT en dicho router usando esa IP.
En mi caso prefiero la segunda opción, aunque puede haber situaciones en los que sea mejor optar por la primera.

Con eso ya tendremos un laboratorio plenamente funcional en lo que se refiere a equipamiento de red Cisco. Sin embargo queda por describir lo que a mi juicio es una de las características más potentes de GNS3: su capacidad de integrar máquinas virtuales de Virtualbox. Gracias a ello, si no tenemos acceso a firmwares de Cisco siempre podemos utilizar appliances "open source" basados en arquitectura PC como Vyatta, Open vSwitch, Endian o Untangle, con los que simular routers, switches y cortafuegos en nuestros laboratorios. Por supuesto, también podremos colocar las imágenes virtuales de nuestros Linux y Windows en cualquuier punto de nuestra topología simulada haciendo de equipos finales. Eso sí, si pensamos usar muchos dispositivos de Virtualbox simultáneamente en nuestros laboratorios ya podemos ir equipando nuestro ordenador con toda la RAM que podamos, la vamos a necesitar.

Para empezar, tenemos que crear en Virtualbox las imágenes virtuales que queramos introducir en GNS3. Para no andar reinstalando una y otra vez las máquinas virtuales lo mejor es crear una máquina virtual con la configuración base para todos nuestros laboratorios y luego, cuando queramos hacer un laboratorio concreto, hacer un clon enlazado de la máquina base. Al usar un clon enlazado ahorraremos espacio de disco duro ya que en el clon sólo se almacenarán los datos diferenciales con respecto a la imagen base. De esa manera podremos tener múltiples clones de una misma máquina base a un coste irrisorio de disco duro.

Una vez que tengamos las máquinas virtuales creadas tenemos que importarlas en GNS3 mediante "Edit -> Preferences -> Virtualbox -> VirtualBox Guest".



Allí crearemos un objeto de GNS3 y lo enlazaremos a la máquina de virtualbox que deseemos definiendo además cuantos interfaces de red queremos que tenga el objeto. Por lo que he visto, el combo box que muestra las máquinas de virtualbox a la que queremos asociar el objeto ("VM List" en la foto) no siempre se inicia bien y se queda vacío, en ese caso hay que pulsar el botón "Refresh VM List" para actualizarlo. Ahora viene lo más raro del asunto y con lo que he tenido que hacer bastantes pruebas hasta dar con la clave. Por lo que he visto, los objetos deben tener como mínimo dos tarjetas de red (NICs). Reconozco que la razón no acabo de tenerla clara, pero buceando por Internet he llegado a la conclusión de que se debe a que se dedica un interfaz a la comunicación interna de la máquina de Virtualbox con GNS3 y otra para hacer de interfaz virtual con la red del laboratorio. Una vez fijado el número de interfaces que queremos que tenga el objeto pulsaremos "Save" y "OK".

En teoría, en Virtualbox no hay que hacer nada, pero si a la configuración de interfaces que tenemos fuera de GNS3 se mezcla con la que crea este podemos acabar teniendo un montón de interfaces con distintas configuraciones corriendo en el laboratorio, lo que puede resultar bastante confuso. Para simplificar las cosas, lo que suelo hacer antes de arrancar mis máquinas virtuales en GNS3 es desactivar todos los interfaces que tienen configurados en Virtualbox poniendolos en "No conectado" y quitando el check de "Habilitar adaptador de red". Parece raro, pero lo cierto es que aunque dejemos sin interfaces la máquina virtual en VirtualBox GNS se encarga de crear dos por su cuenta. No es muy intuitivo, pero a mi me funciona así.

Una vez en la ventana de diseño podemos situar la máquina recién creada arrastrando el icono de "VirtualBox Guest" y seleccionando el nombre del objeto que hemos creado en los párrafos anteriores. A partir de ahí, para conectar los objetos entre si, pulsaremos el último botón de la izquierda, el que tiene un icono de un conector RJ-45 y seleccionaremos el modo de conexión "Manual". He probado el resto de los modos de conexión pero reconozco que no me resultan nada intuitivos, por eso prefiero sencillamente el "Manual".

Una vez establecidas las conexiones, arrancaremos las máquinas virtuales y las configuraremos para la red del laboratorio. Al arrancar las máquinas, desde VirtualBox veremos que en ellas se crea un interfaz del tipo "Generic Driver" y otro que será el que se conecte a nuestro laboratorio virtual y que deberemos configurar para que se conecte al resto. Saber cual es cual dentro de la máquina virtual de GNS3 tiene algo de prueba y error, o al menos yo no he acabado de ver un patrón claro de asignación, pero con dos interfaces tampoco hay muchas posibilidades. Configuramos un interface y si se hace ping al resto de los elementos del laboratorio significa que hemos dado con el que nos interesaba y que podemos olvidarnos del otro y hacer como si no existiera. Si hemos configurado el laboratorio para que cuente con un servidor de DHCP y nuestra máquina virtual para hacer uso de él, identificar el interfaz con conectividad será mucho más fácil.

Aún con todos estos trucos, GNS3 es tremendamente potente y la riqueza de laboratorios que podemos crear sólo tiene su límite en la cantidad de máquinas virtuales que podamos ejecutar simultáneamente en nuestra memoria RAM.