Instalar Ubuntu sin CDs, DVDs ni dispositivos USB utilizando únicamente la red (PXE)
Publicado por el Sábado, 05 de Julio de 2008
El título ha quedado un poco largo, pero eso es exactamente lo que acabo de hacer hace un rato, y como me parece algo interesante, voy a explicar brevemente cómo conseguirlo.
La base del proceso es PXE, que para definirlo en pocas palabras viene a ser un "modo de arrancar un ordenador" utilizando para ello únicamente el interfáz de red. Como podéis ver en el enlace a la wikipedia, PXE es básicamente una mezcla de DHCP y TFTP.
Paso 1: el ordenador ha de ser capaz de arrancar desde la red
Para poder instalar nuestro sistema utilizando esta tática, es necesario que éste sea capaz de hacer el boot desde un dispositivo de red. La mayoría de los PCs soportan esta característica, por lo que no debería de ser un requisito difícil de satisfacer. Una vez que nos aseguremos de que el PC "sabe arrancar desde la red", ya solo nos falta instalar un servidor que le responda adecuadamente a sus peticiones.
Paso 2: instalar el servidor
En este caso, el ordenador que va a servir los ficheros de arranque es un humilde PC con windows ya instalado, por lo que la herramienta que utilizaremos es TFTPD32. Esta herramienta es una de esas pequeñas joyas que a cambio de muy pocos KB son capaces de hacer un montón de cosas, como podéis observar en la página del autor.
Una vez descargado el programa, ponerlo a funcionar es tan simple como crear una carpeta, digamos que c:\tftp y copiar en ella el fichero tftpd32.exe. Lo ejecutamos y ya tenemos el servidor andando. Así de fácil.
Paso 3: descargarse la imagen de ubuntu peparada para estas labores
El siguiente paso será descargarse la imagen de ubuntu lista para ser servida utilizando PXE. Para conseguir este objetivo tendremos que descargarnos la carpeta ubuntu-installer que podremos encontrar en el respositorio de ubuntu. En mi caso particular, esta carpeta podía descargarse de:
ftp://archive.ubuntu.com/ubuntu/dists/hardy/main/installer-i386/current/images
Paso 4: configurar el servidor
Una vez descargada esta carpeta, deberemos de copiarla en c:\tftp. Además, debemos de asegurarnos de:
- copiar a c:\tftp la carpeta pxelinux.cfg desde ubuntu-installer/i386/
- copiar a c:\tftp el fichero pxelinux.0 desde ubuntu-installer/i386/
Ahora ya podemos configurar el tftpd32. En la pestaña DHCP, deberemos poner 'pxelinux.0' en el campo boot file y deberemos rellenar el resto de valores ajustándose a la realidad de nuestra red. Es importante que el valor del campo 'IP pool starting address' sea una IP válida en nuestra red y que se refiera a un rango de IPs no utilizado en la misma. Una vez cubiertos todos los campos, pulsamos save y ya tenemos nuestro servidor configurado. Así de fácil,
Paso 5: arrancar el pc que queremos instalar
Con nuestro servidor perfectamente configurado, ya podemos arrancar el pc en el que queremos instalar ubuntu. Si todo va bien y los cables están bien enchufados, podremos ver que comienzan a aparecer entradas en la pestaña 'Log viewer' de tftpd32. Se establece la comunicación entre el PC que arranca utilizando PXE y nuestro servidor. Al cabo de unos instantes, el PC que está tratando de arrancar acaba recibiendo por TFTP la imagen de instalación basada en red de ubuntu. A partir de ahi sólo nos queda continuar con una instalación basada en red de lo más normal, (lenta), y aburrida.
¿Quieres trabajar en Trabe Soluciones?
Publicado por el Sábado, 12 de Abril de 2008
Trabe Soluciones está creciendo. Ahora que nos vamos a mudar a unas oficinas más amplias tenemos una vacante. La oferta de trabajo que estamos distribuyendo es la siguiente.
Buscamos personas para trabajar en A Coruña.Trabe te necesita
Nos gustaría que supieses desarrollar aplicaciones web MVC con J2EE y Ruby on Rails, que controlases de HTML, CSS y Javascript, que tuvieses conocimientos de diseño gráfico, que administrases servidores, que te sintieses cómodo en Linux, que te gustase usar software libre,...
Si esto te describe ven corriendo. En caso contrario, no te preocupes, valoramos la experiencia que tengas, pero también nos interesa tu pasión y tus ganas de aprender, de trabajar de una manera diferente, de asumir responsabilidades y de crecer con nosotros.
Te ofrecemos unas excelentes condiciones. Todo lo que te ofrecen el resto de ofertas de trabajo y mucho más: horario flexible, oficina céntrica(nada de polígonos), plantilla joven, café a media manaña, no llevamos corbata ni traje... Nos importa tu calidad de vida.
Si quieres saber más de nosotros, puedes echar un vistazo a nuestra web (http://www.trabesoluciones.com) o a nuestro blog (http://4trabes.com), o directamente contactar con nosotros para plantearnos cualquier duda (contacto@trabesoluciones.com).
Esperamos tu curriculum en rrhh@trabesoluciones.com.
Ya han llegado los primeros CVs. ¿A qué esperáis para enviar el vuestro?
Google Chart API + ruby = gchartrb
Publicado por el Martes, 01 de Abril de 2008
En nuestro último proyecto necesitamos incluir varios tipos de gráficas (líneas, barras y alguna tarta). De entre las múltiples posibilidades existentes hemos decidido usar el API de gráficas de Google (Google Chart API) que nos ofrece un montón de posibiliades de manera sencilla, fiable, gratuita e ilimitada. La única peculiaridad de su uso es que los datos a representar deben ser codificados antes de enviarlos al servidor de gráficas. Esto no representa mayor problema, menos aún cuando existen varios wrappers distribuidos como gemas o plugins que hacen este trabajo por nosotros, como son: gchartrb, Googlecharts o Google Charts on Rails.
Nosotros estamos usando gchartrb, porque entendemos es la más completa y documentada y porque su API nos agrada más. Por ejemplo, para pintar una sencilla gráfica como la que sigue…
... necesitamos un código como este:
PIE_COLORS = %w(9bd500 a4d520 b0d54b bbd575 c7d5a0)
data = Post.count(:group => :user_name, :order => 'count_all desc')
pie_chart = GoogleChart::PieChart.new('300x100') do |chart|
data.each_with_index do |row, i|
chart.data "#{row[0]} (#{row[1]})", row[1], PIE_COLORS[i]
end
end
image_tag pie_chart.to_url
1000 Galegos Globais... lo celebramos con más Galicia Global
Publicado por el Lunes, 31 de Marzo de 2008
Galicia global ha llegado a los mil usuarios. Lenta pero segura la comunidad de Gallegos Globales ha llegado a superar la barrera de los tres dígitos. Y para celebrarlo nada mejor que anunciar que desde ISOCGal y la Xunta ya nos han pedido que desarrollemos algunas novedades para este año. Ya tenemos algo pensado… os mantendremos informados.
Instalar Windows 2000 sobre VirtualBox
Publicado por el Miércoles, 26 de Marzo de 2008
Este post va dedicado a todos aquellos que, como yo, no suelen leerse las "guias de instalación". Si además pretenden instalar una imagen de Windows 2000 sobre VirtualBox en un ordenador tirando a rápido, es posible que tengan un problema.
Al principio parece que todo va bien, pero llega un momento en que el proceso de instalación hace que el PC se reinicie. Al arrancar de nuevo, la instalación vuelve a comenzar. Nos quedamos atrapados en un bucle infinito del que no es posible salir.
Después de perder algún tiempo imaginando qué podía estar pasando, he llegado al origen del problema (manual de VirtualBox):
11.2.2 Windows 2000 installation failuresWhen installing Windows 2000 guests, you might run into one of the following issues:
• Installation reboots, usually during component registration.
• Installation fills the whole hard disk with empty log files.
• Installation complains about a failure installing msgina.dll.
These problems are all caused by a bug in the hard disk driver of Windows 2000. After issuing a hard disk request, there is a race condition in the Windows driver code which leads to corruption if the operation completes too fast, i.e. the hardware interrupt from the IDE controller arrives too soon. With physical hardware, there is a guaranteed delay in most systems so the problem is usually hidden there (however it should be possible to reproduce it on physical hardware as well). In a virtual environment, it is possible for the operation to be done immediately (especially on very fast systems with multiple CPUs) and the interrupt is signalled sooner than on a physical system. The solution is to introduce an artificial delay before delivering such interrupts. This delay can be configured for a VM using the following command:
VBoxManage setextradata
This sets the delay to one millisecond. In case this doesn’t help, increase it to a value between 1 and 5 milliseconds. Please note that this slows down disk performance. After installation, you should be able to remove the key (or set it to 0).
Siguiendo las instrucciones del manual, todo parece funcionar correctamente. A veces puede ser útil leer un manual...
Zed's so fucking awesome
Publicado por el Domingo, 17 de Febrero de 2008
No sé si Zed es tan “awesome”, pero “funny” lo es sin duda. Que cachondo el papá de mongrel.
PD: No os perdáis el post Rails is a ghetto que lo ha convertido en “infame”.
Velocidad psicológica
Publicado por el Jueves, 14 de Febrero de 2008
Mi ordenador no se mueve. Va lento. ¿Cómo es posible? Si apenas tienes 5 meses. Si es una máquina de matar.
Tranquilo. Tu ordenador está en perfecto estado y va tan rápido como siempre. Es un problema de velocidad psicológica. Cuanto más trabajo tienes y más rápido quieres ir, más lento te parece tu equipo. Y no, lo siento, trabajar menos o más despacio no es la solución al problema.
Excel no puede ser una fuente de datos normalizada
Publicado por el Domingo, 10 de Febrero de 2008
Sergio, te acompaño en el sentimiento.
NetBeans 6.0: plantillas de código
Publicado por el Sábado, 09 de Febrero de 2008
Las plantillas de código (code templates en inglés) son pequeños snippets de código fuente que se expanden automáticamente permitiéndonos modificar determinadas partes, mientras que otras partes se mantienen fijas. Aunque son una funcionalidad disponible en todo editor que se precie, no todo el mundo parece darse cuenta de su potencial: las plantillas de código son a los editores / IDEs lo que el DRY es a la programación.
Las plantillas se invocan normalmente escribiendo una pequeña palabra en el editor y pulsando una tecla o una combinación de teclas para “dispararlas”. Para quien no conozca el mecanismo, las dos siguientes imágenes sirven como ejemplo: al escribir en el editor del NetBeans la palabra def y pulsar a continuación la tecla tab (primera imagen), obtenemos la expansión de una definición de un método en Ruby (segunda imagen).
El cursor queda situado automáticamente en method_name, permitiéndonos escribir el nombre que queramos, y una vez pulsamos enter o bien tab de nuevo, el cursor pasa al cuerpo del método, para que podamos seguir codificando.
NetBeans trae una serie de plantillas definidas por defecto, pero a través del menú Tools > Options > Editor > Code templates podemos acceder a un panel en el que, además de poder ver todas esas plantillas predefinidas, podemos crear las nuestras propias. Hay bastantes opciones a la hora de controlar cómo se expande la plantilla; para una descripción más exhaustiva de todas ellas, aquí está la página del wiki de NetBeans dedicada a las RubyCodeTemplates.
Aquí sólo vamos a mostrar la definición de la plantilla def tal y como viene “de serie” con el NetBeans:
La sintaxis es sencilla:
- El código (Ruby, RHTML, CSS, Java, etc.) se escribe tal cual y quedará así al expandir la plantilla.
- Los valores “plantillados” se definen mediante ${nombre default=”valor_por_defecto”}; estos valores se expandirán al valor default, pero podremos modificarlos cambiando ese valor por defecto por lo que nosotros queramos. Además, al poder nombrarlos, podremos hacer referencia a ellos en varias partes de la plantilla (ver ejemplo más adelante).
- A mayores, existen una serie de valores predefinidos que nos permiten: situar el cursor al terminar la expansión (${cursor}); incrustar el código seleccionado (${selection}); incrustar el nombre del fichero en el que se está realizando la expansión (${file}) etc.
Las posibilidades son muchas (no tantas como en el TextMate, quizás, pero muchas al fin y al cabo :P). Como ejemplo, sirvan un par de plantillas que utilizamos muy a menudo en nuestros editores:
Plantilla b
<% ${0 default="block"} do %>
${selection}${cursor}
<% end %>
Con esta plantilla definimos bloques en Erb, algo que hacemos muy a menudo ya que normalmente usamos helpers de este tipo para capturar las distintas partes de nuestro layout.
Una cosa que hemos aprendido con la experiencia: algunas plantillas, se utilizan tanto para rodear código ya existente como para generar código desde cero. En esos casos el truco de poner ${selection}${cursor} permite utilizar la plantilla para ambos fines. ¡Y otra cosa importante! Las plantillas que incluyen el parámetro ${selection} se pueden invocar de dos maneras: utilizando una tecla (p.e. tab), en cuyo caso contarán con una selección vacía, o utilizando la combinación Alt+Enter. En funcionamiento:
Plantilla t
<${0 default="div"} id="${1 default=""}">${selection}${cursor}</${0}>
Esta plantilla la utilizamos para generar tags HTML con un id. En este caso el parámetro 0 se sustituye con el nombre del tag, tanto en la apertura como en el cierre. El parámetro 1 se sustituye por el id del elemento. Y de nuevo utilizamos el truquillo de la selección para poder rodear HTML si lo deseamos.
Son sólo dos ejemplos, pero en nuestro trabajo diario utilizamos un buen puñado de plantillas que nos permiten acelerar las tareas de codificación y evitar errores al teclear. Pensad en el código que repetís constantemente y definid vuestras propias plantillas para facilitaros la tarea; una vez lo hagáis no podréis vivir sin ellas.
¿Qué fuente es esa?
Publicado por el Lunes, 04 de Febrero de 2008
david: ¿Qué fuente es esa?
asís: Es consolas
david: ... me gusta…
NetBeans 6.0: "IDEal de la muerte"
Publicado por el Lunes, 04 de Febrero de 2008
Por si el título no lo deja claro, lo repito aquí: NetBeans se ha convertido desde hace unos meses en la opción a la hora de elegir un IDE para desarrollar aplicaciones Rails. Al menos ha sido nuestra elección y, por lo que puedo decir tras varios meses de trabajo, primero con las versiones beta y ahora con la release definitiva, creo que hemos acertado de pleno al abandonar nuestro querido Aptana RadRails y pasarnos a la “competencia”.
NetBeans proporciona un entorno de trabajo muy cómodo, manejable y potente, del que me gustaría destacar las siguientes características:
- Integración con SVN de serie
- Syntax highlight
- Autocompleción de tipos, variables, funciones, parámetros, columnas de BD, etc.
- plantillas inline à la Textmate (o casi, vale)
- Hints sobre posibles errores en el código
- Control de los generadores Rails y las tareas Rake desde el propio IDE
- Depuración de código Rails
Es una pequeña lista. Para obtener información más detallada sobre NetBeans podéis echarle un ojo a su propia página (el enlace está ahí atrás, donde dice “netbeans” :-P) o bien googlear un rato: hay un montón de gente ahí fuera encantados con este magnífico IDE para Rails.
De todos modos, por aquello de dejar salir mi lado negativo a pasear, antes de despedirme voy a comentar lo que menos me gusta de NetBeans en comparación con RadRails (es decir, Eclipse)
- La vista de sincronización de SVN. Prefiero la vista de los Eclipse, me da una noción más clara de qué ha cambiado (NetBeans muestra un listado plano de los ficheros con cambios, mientras que el plugin de Eclipse permite ver los ficheros en un árbol, colgando de sus carpetas padre)
- La gestión de las preferencias. En Eclipse se puede controlar casi cualquier aspecto del IDE, y encontrar cada preferencia es muy sencillo gracias al maravilloso sistema de búsqueda integrado en los diálogos de configuración. Por contra, encontrar en el NetBeans un determinado parámetro es una tarea de rastreo casi lineal hasta dar con ella que puede llegar a desesperar (por ejemplo, cambiar los atajos de teclado se convierte en un infierno)
- Por último, falta una opción (al menos yo no he conseguido encontrarla) que permita enlazar el editor de código con el árbol del proyecto. Se puede seleccionar el fichero que se está editando en el árbol del proyecto utilizando una combinación de teclas (ctrl+shift+1 si mal no recuerdo), pero a veces se hace tedioso. Aquí de nuevo gana el Eclipse, al permitir enlazar o desenlazar el editor y el árbol al libre albedrío del desarrollador, como debe ser.
Efectivamente, son tres pijadas. Y por eso mismo recomendamos NetBeans como IDE para Rails: porque los únicos argumentos que tenemos en contra no son argumentos, son pijadas.
(Y ya para terminar, una cita de la introducción a La lucha contra el demonio, de Stefan Zweig, a cuento de las comparaciones) [...] la comparación enriquece, pues realza los valores, dando una serie de reflejos que, alrededor de las figuras, forman como un marco de profundidad en el espacio.
El infierno de los valores cableados
Publicado por el Martes, 29 de Enero de 2008
A veces me pregunto como es posible que hoy en día la gente siga cableando valores en su código.
Último ejemplo que me he encontrado: acts_as_sphinx. Este simpático plugin permite de manera muy sencilla que nuestros modelos active record lancen búsquedas contra un sphinx. Es sencillo, funciona y se adapta muy bien a lo que buscamos para una aplicación que estamos desarrollando y por eso lo usamos. Sin embargo, no es perfecto. Y lo que me “cablea” es que la caguen en algo tan trivial. Digamos que este plugin nos “obliga” a que el fichero de configuración de sphinx sea $RAILS_ROOT/config/sphinx.conf (mala idea porque no se puede usar “de serie” una configuración diferente para producción y desarrollo, aunque esa ya es otra historia).
acts_as_sphinx_tasks.rake:
desc "Start searchd server"
task :start do
if File.exists?('/var/run/searchd.pid')
puts 'Sphinx searchd server is already started.'
... y así varias veces más ...
Ahora el fichero de configuración de ejemplo/documentación de sphinx:
searchd {
...
# a file which will contain seachd process ID
# used for different external automation scripts
# MUST be present
pid_file = @CONFDIR@/log/seachd.pid
...
Me parece muy bien que a los autores del plugin les guste que el fichero de pid esté en /var/run/searchd.pid, pero yo no lo coloco ahí. ¿Era tan difícil, ya que sabes dónde localizar el fichero de configuración, extraer de él el nombre del fichero con el pid? Yo creo que no. Puede hacerse en 5 líneas. Menos incluso. Y menudo cambio.
Y alguién dirá que no pasa nada, que redefina las tareas rake o que modifique el plugin. Y yo diré que bien, que de acuerdo, pero que, como plugin que es, debería ofrecer una funcionalidad mínima y correcta, sin que me obligue a hacer nada a mayores (porque para eso es el código de terceros, para no tener que hacerlo uno mismo). No pretendo cambiar el funcionamiento del plugin. Sólo que haga lo que dice que hace correctamente.
Dejo en la recamara un ejemplo de cableo salvaje de valores en una libreŕia bastante conocida. Un día me animo y cuento la historia. Que no tiene desperdicio.
Instalando Fedora (nunca más Core) 7 en un Dell Dimension C521 o el infierno de la ATI X1300
Publicado por el Miércoles, 29 de Agosto de 2007
Hace menos de una semana hemos renovado el parque de equipos de Trabe. Nos hemos decantado por unos Dell Dimension C521 con la siguiente configuración:
- AMD Athlon X2 64 4400+
- 300GB de disco duro
- 2GB de memoria
- Tarjeta gráfica ATI X1300 256MB
- TFT 22” (1680×1050) + TFT 17” (1280×1024)
Los equipos, en cuanto que “electrodomésticos”, son una maravilla: pequeños (dento de un orden), silenciosos, e incluso, si se me apura, bonitos (aunque esto es para gustos, claro). Pero el problema de los ordenadores es, precisamente, que no son electrodomésticos (me estoy desviando del tema, así que lo dejo para otro post).
A lo que iba. Los equipos traen un Windows Vista Bussiness preinstalado. Un operativo como otro cualquiera, que tarda mucho en arrancar y en cerrarse. Y poco más puedo decir sobre el Vista, porque lo primero que hemos hecho ha sido instalar una distribución linux, una Fedora 7 para ser más concretos. Obviando los pasos básicos de la instalación, y dejando a un lado algún que otro problema puntual con aplicaciones concretas (léase Firefox, léase Adobe Acrobat Reader, léase Eclipse), sí me gustaría destacar lo complicado que resultó poner a funcionar el escritorio (KDE algunos, GNOME otros) en los dos monitores a las resoluciones adecuadas. Por si alguien se encuentra con el problema, aquí queda enlazada una solución, que pasa por parchear el driver cambiando unos cuantos bits aquí y allí… algo muy natural, evidente y nada complicado ¬¬. Tras seguir los pasos indicados en el post citado, el escritorio funciona perfectamente (si dejamos a un lado unos extraños parpadeos o flashes que se producen cada n minutos), extendido a ambos monitores, como debe ser.
Instalando CruiseControl.rb, una herramienta de Integración continua para aplicaciones Ruby on Rails
Publicado por el Jueves, 26 de Julio de 2007
CruiseControl.rb es el porte a Ruby on Rails de CruiseControl, una conocida herramienta de integración continua, que utilizamos en Trabe Soluciones. En este post os mostraré, a modo de ejemplo, como está montado en nuestras oficinas.
Integración Continua
Martin Fowler define la integración continua (Continuous Integration en inglés) como:
... a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily – leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly…
es decir, un proceso automático que verifica que los cambios introducidos en el repositorio de trabajo por los desarrolladores son correctos.
CruiseControl.rb consta de dos partes básicas. Un grupo de
Montando la herramienta
CruiseControl.rb debe instalarse en un sistema que disponga de Ruby, y sus herramientas asociadas: RDoc, Rake, RubyGem, etc. Además para poder monitorizar aplicaciones Rails debemos instalar los gems de Rails y aquellos gems requeridos por dichas aplicaciones.
Instalando CruiseControl.rb
Para abreviar, pondré los comandos bash necesarios. Son fáciles de seguir. En caso de duda: Google
[root@localhost]$ adduser trabe [root@localhost]$ passwd trabe [root@localhost]$ su - trabe [trabe@localhost]$ wget http://rubyforge.org/frs/download.php/19237/cruisecontrolrb-1.1.0.tgz [trabe@localhost]$ tar xvfz cruisecontrolrb-1.1.0.tgz [trabe@localhost]$ mkdir .versions [trabe@localhost]$ mv cruisecontrolrb-1.1.0 .versions [trabe@localhost]$ ln -s .versions/cruisecontrolrb-1.1.0 cruisecontrolrb [trabe@localhost]$ cd cruisecontrolrb [trabe@localhost]$ ./cruise start
Si todo ha ido bien el servidor arrancará y en el puerto 3333 de la máquina con un navegador veréis una pantalla como la que sigue. Crear un directorio de versiones y un enlace simbólico no es obligatorio (pero es algo que nosotros acostumbramos a hacer para facilitar las actualizaciones del software).
CruiseControl.rb como servicio del sistema
Para este paso necesitamos tener instalado el gem de Mongrel en nuestro sistema (gem install mongrel -y), ya que los
[trabe@localhost]$ cp daemon/cruise.sample daemon/cruise [trabe@localhost]$ vi daemon/cruise
Editamos el fichero daemon/cruise (con vi, emacs, nedit o cualquier otro, al gusto) y realizamos algunos cambios. Buscamos el fragmento:
def cruise_path # NOTE: you must specify $CCRB_HOME here # "/home/gigix/Projects/cc.rb" raise "Please specify your $CCRB_HOME path in this method." end
.. y, como nos insta, lo cambiamos por:
def cruise_path "/home/trabe/cruisecontrolrb" end
Añadimos, a mayores, al comienzo del fichero la información necesaria para que la herramienta chkconfig funcione correctamente. Los
#!/usr/bin/env ruby # chkconfig: 35 66 34 # description: Controla el servicio de CruiseControl.rb
Opcionalmente podemos modificar la línea que invoca al servidor para que utilice el usuario
when 'start' cd cruise_path system "./cruise start -d" exit 0
... pasa a ser …
when 'start'
cd cruise_path
system "su trabe -c '#{cruise_path}/cruise start -d'"
exit 0
Sólo queda instalar el servicio y arrancarlo por primera vez.
[trabe@localhost]$ exit [root@localhost]$ ln -s /home/trabe/daemon/cruise /etc/init.d/cruise [root@localhost]$ chkconfig --add cruise [root@localhost]$ service cruise start
Añadiendo proyectos
Para añadir un proyecto, por ejemplo Queue.it, debemos utilizar la herramienta cruise.
[trabe@localhost]$ ./cruise add QueueIt -u svn://svn/projects/queueit
Esto generará un directorio /home/trabe/cruisecontrolrb/projects/QueueIt con el proyecto. Sus contenidos relevantes son los siguientes:
work: Copia de trabajo local del proyecto (a partir de la copia remota en SVN)build-*: Logs de cada buildcruise_config.rb: Configuración de build del proyecto.
Respecto a la configuración, ya que en principio será idéntica para todos los proyectos, lo que haremos será mantener un fichero de configuración común.
# /home/trabe/cruisecontrolrb/projects/cruise_config.rb Project.configure do |project| # Hacer ping a Subversion buscando nuevas versiones cada 30 minutos # (por defecto son 30 segundos) project.scheduler.polling_interval = 30.minutes end
Cada nuevo proyecto utilizará este fichero, a menos que se decida que debe tener una configuración propia.
[trabe@localhost]$ cd QueueIt [trabe@localhost]$ rm cruise_config.rb [trabe@localhost]$ ln -s ../cruise_config.rb cruise_config.rb
El dashboard
Una vez añadido el proyecto, se creará el primer build y podremos ver sus resultados en el dashboard.
En adelante, cada cambio que haya en el SVN será detectado y se generará un nuevo build. También es posible forzar la creación de estos builds desde el dashboard. Los resultados del proceso pueden obtenerse mediante un feed RSS.
Modificando la tarea de build por defecto
CruiseControl.rb reacciona ante las nuevas versiones del código en el repositorio intentando ejecutar, por este orden:
1. La tarea de Rake definida en el fichero cruise_control.rb
project.rake_task = 'custom'
2. Una tarea cruise definida en el Rakefile del proyecto
task :cruise => ['test'] do; end
3. Ejecuta la tarea cc:build que CruiseControl.rb inyecta en nuestros proyectos de modo transparente mediante un wrapper no intrusivo. Esta tarea por defecto es equivalente a una tarea cruise tal que :
task :cruise => ['db:test:purge', 'db:migrate', 'test'] do; end
En nuestro caso, existe un comportamiento por defecto de todos nuestros proyectos y no queremos, por tanto, tener que escribir en cada uno de ellos una tarea cruise personalizada o configurar la tare a ejecutar. Lo que vamos a hacer es modificar la tarea cc:build con nuestro comportamiento adicional. Añadiremos el siguiente código debajo de la línea 38 del fichero /home/trabe/cruiserb/tasks/cc_build.rake:
CruiseControl::invoke_rake_task 'stats'
if Rake.application.lookup('trabe:doc')
CruiseControl::invoke_rake_task 'trabe:doc'
else
raise "'trabe:doc' task not found. Cannot build the documentation"
end
que es equicalente a tener en cada proyecto monitorizado una tarea Rake tal que:
task :cruise => ['stats', 'trabe:doc', 'db:test:purge', 'db:migrate', 'test'] do; end
Es decir, lo primero que haremos siempre, será generar las estadísticas de código (que aparecerán en el log del dashboard, para vergüenza de aquellos que descuiden los tests) y la documentación RDoc. Ésto lo hacemos a través de una tarea que tienen todos nuestros proyectos Rails definida en $RAILS_APP_ROOT/lib/tasks/trabe.rake, que genera la documentación con nuestra propia plantilla y en UTF-8 (para aquellos proyectos con documentación en castellano):
namespace :trabe do
#desc "Creates the RDOC with UTF-8encoding and Trabe template"
Rake::RDocTask.new("doc") do |rdoc|
rdoc.rdoc_dir = 'doc/queueit_doc'
rdoc.title = "Queue.it Rdoc"
rdoc.template = 'trabe'
rdoc.options << '--charset' << 'utf-8'
rdoc.options << '--line-numbers'
rdoc.options << '--inline-source'
rdoc.options << '--all'
rdoc.rdoc_files.include('doc/README')
rdoc.rdoc_files.include('app/**/*.rb')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/fcgi_handler.rb')
end
end
Truco: Ya que hemos generado la documentación, podemos aprovecahr para publicarla a través de un servidor web (apache en nuestro caso). La configuración es sencilla y la vamos a obviar porque el post ya se está haciendo interminable.
Monitorizando los proyectos
En Trabe monitorizamos los builds a través del
Mejoras futuras
Si el tiempo lo permite intentaremos realizar mejoras que aprovechen al máximo la infraestructura, como pueden ser:
- Integrar CruiseControl.rb en nuestra aplicación de intranet, donde gestionamos toda la información de los proyectos (tareas, tiempos, etc).
- Desplegar versiones de prueba de las aplicaciones en un servidor al efecto utilizando Capistrano con cada build.
Conclusiones
CruiseControl.rb es una herramienta muy sencilla que todavía puede mejorar mucho, pero su funcionamiento actual es más que suficiente para satisfacer una necesidad real dentro del proceso de desarrollo del software: la integración continua.
Cabe destacar que CruiseControl.rb permite monitorizar proyectos que utilizan otras herramientas a parte de Rake. Es posible, por ejemplo, monitorizar proyectos Java que utilicen Ant o Maven. El control de proyectos no Rails exige un esfuerzo adicional de configuración, pero merece la pena intentar utilizar una única herramienta para controlar todos los proyectos de la organización, sea cual sea la tecnología que uses.
Echadle un vistazo y sacad vuestras propias conclusiones. Sólo necesitais diez minutos para ponerlo en marcha y probar con un par de proyectos.
Sincronizar con un ftp utilizando perl
Publicado por el Lunes, 28 de Mayo de 2007
Cuando necesitamos mantener dos sistemas de ficheros sincronizados hay varias opciones razonables. Podemos utilizar alguna utilidad tipo rsync, o multitud de aplicaciones de propósito específico. Incluso podemos utilizar un cvs o svn para conseguir este fin. Pero cuando el "servidor remoto" solo es accesible a través de ftp las opciones se reducen bastante.
Cuando es razonable suponer que el tamaño de los datos va a ser escaso, podemos optar por hacer backups periódicos de la totalidad del sistema de ficheros, y luego restaurarlos en el sistema a mantener sincronizado. Pero cuando el sistema de ficheros va a contener ficheros grandes, eso no es una gran idea.
El script perl que se muestra a continuación no es ni mucho menos una solución general de sincronización. Tampoco considera todos los casos posibles, ni hace sincronización recursiva, pero es una solución que funciona correctamente en el escenario para el que fué creada.
El funcionamiento es muy sencillo:
- El script se conecta al servidor ftp indicado en las variables de configuración..
- Para cada archivo del sistema remoto comprueba si existe en el sistema local. Si no existe lo descarga. Si existe y su fecha es anterior a la instancia del sistema remoto, también lo descarga.
- Para cada archivo del sistema local comprueba si existe en el sistema remoto. Si no es así, lo elimina.
Partiendo de la premisa de que en el sistema local NUNCA se realizan cambios sobre los ficheros, al final del proceso tendremos en la carpeta local una réplica del contenido del sistema remoto, minimizando las transferencias de ficheros en la medida de lo posible.
A continuación se incluye el script en cuestión:
#!/usr/bin/perl -w
use strict;
use warnings;
use Net::FTP;
# Algunas variables
my $host = "dirección_host";
my $user = "usuario_ftp";
my $pass = "contraseña";
my $local_app_root = "ruta_local";
my $remote_app_root = "ruta_remota";
# Conectamos al servidor ftp
print "Conectando al servidor $host " ;
my $ftp = Net::FTP->new($host, Passive => 1, Debug => 0 ) or die "Imposible conectar al servidor FTP en $host";
$ftp->login( $user, $pass ) or die "..fallo en la autenticación $!";
print "[OK]\n";
# Sincronizamos las carpetas de ficheros
print "\n:::: Sincronizando Ficheros ::::\n";
repo_sync($ftp, $local_app_root, $remote_app_root);
# Desconectamos del ftp
print "\n\nDesconectando...";
$ftp->quit;
print "[OK]\n";
# Funcion para sincronizar FTP<-Local
sub repo_sync {
my $ftp = shift;
my $local_path = shift;
my $remote_path = shift;
my $rtime;
# Obtenemos el listado de ficheros Remotos
$ftp->cwd($remote_path);
my @remote_files = $ftp->ls();
# Bajamos todo lo nuevo
for my $file (@remote_files) {
if ( !( $rtime = $ftp->mdtm($file) ) ) {
# Dado quer el archivo SIEMPRE existe, y mdtm solo es false cuando el archivo no existe o
# bien cuando es un directorio, en este casp estamos en un directorio.
# No hacemos nada en este caso
}
else
{
# Es un fichero, comenzamos a sincronizar
print "\nSincronizando: $file\n";
if ( !( my $ltime = (stat("$local_path/$file") )[9] ) ) {
# No existe el fichero en el repositorio local
print "-> No existe en repositorio local";
print ".Actualizando...";
# Obtenemos el fichero por ftp
$ftp->get ($file, "$local_path/$file");
print "[OK]";
}
else
{
# Existe el fichero en el repositorio local
print "-> Existe en repositorio local";
if ($rtime > $ltime) {
# La copia local no está al día
print ". No está al día. Actualizando...";
$ftp->get ($file, "$local_path/$file");
print "[OK]";
}
else {
print". Está al día";
}
}
}
}
# Borramos lo que ya no está en el repositorio remoto, para ello necesitaremos iterar sobre los ficheros del sistema local
my (@local_files, $f);
opendir DIR, $local_path or
die "Imposible abrir $local_path: $!\n";
while($f = readdir DIR) {
if(-d "$local_path/$f"){
# Esto son directorios. De nuevo no nos interesa tratarlos en nuestro script,
# dejamos este comentario a modo de recordatorio para quien necesite
# hacer algo con ellos
}
else{
# Guardamos los ficheros en un array
push (@local_files, $f);
}
}
# Iteramos sobre los ficheros
for my $file (@local_files) {
if ( !( $rtime = $ftp->mdtm($file) ) ) {
# El archivo NO existe en el repositorio remoto, pues mdtm solo es false cuando el fichero no existe o cuando es
# un directorio, caso imposible en esta rama.
print "\nSincronizando: $file\n->NO existe en el repositorio. Eliminando..." ;
unlink "$local_path/$file";
print "[OK]";
}
}
}
Espero que alguien pueda ahorrarse un rato de trabajo gracias a este post :D
