<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6747698170585092034</id><updated>2011-11-28T00:22:11.877Z</updated><category term='ruby'/><category term='linux'/><category term='subversion ruby script'/><category term='cvs'/><category term='instalacion'/><category term='cliente'/><category term='git'/><category term='derechos'/><category term='colaboración'/><category term='psoe'/><category term='script'/><category term='desarrollo'/><category term='metodología'/><category term='servidor'/><category term='dns apache virtual_host ruby'/><category term='proceso'/><category term='Ley Sinde'/><category term='herramientas'/><category term='gitosis'/><category term='subversion'/><title type='text'>Automatizando el día a día</title><subtitle type='html'>Guía rápida para simplificar la vida de un desarollador web.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-4462871816740302854</id><published>2011-03-18T01:53:00.000Z</published><updated>2011-03-18T01:53:40.626Z</updated><title type='text'>Cerrado por traslado</title><content type='html'>Ya he completado la mudanza. A partir de ahora puedes leerme en &lt;a href="http://ejosafat.com"&gt;Eliminando la (sub)rutina&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-4462871816740302854?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/4462871816740302854/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2011/03/cerrado-por-traslado.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4462871816740302854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4462871816740302854'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2011/03/cerrado-por-traslado.html' title='Cerrado por traslado'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-3707472127834039117</id><published>2011-03-14T19:47:00.000Z</published><updated>2011-03-14T19:47:44.744Z</updated><title type='text'>Estoy de mudanza</title><content type='html'>Alguno me ha comentado que aún está esperando la segunda parte del artículo de herrammientas colaborativas (¡qué bien, hay gente que me lee! :-)&lt;br /&gt;&lt;br /&gt;Voy a tardar un poco más porque estoy mudando mi blog a Posterous (junto con mi página personal). En cuanto esté listo ya les avisaré por aquí. La url de momento es &lt;a href="http://ejosafat.posterous.com"&gt;ejosafat.posterous.com&lt;/a&gt;, pero la definitiva será &lt;a href="http://www.ejosafat.com"&gt;www.ejosafat.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Como dicen los anglosajones, stay tuned!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-3707472127834039117?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/3707472127834039117/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2011/03/estoy-de-mudanza.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3707472127834039117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3707472127834039117'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2011/03/estoy-de-mudanza.html' title='Estoy de mudanza'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-4235490037339703720</id><published>2010-12-27T12:48:00.000Z</published><updated>2010-12-27T12:48:30.672Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='herramientas'/><category scheme='http://www.blogger.com/atom/ns#' term='desarrollo'/><category scheme='http://www.blogger.com/atom/ns#' term='colaboración'/><title type='text'>Herramientas de colaboración online (I)</title><content type='html'>&lt;p&gt;Recientemente di un mini-taller sobre herramientas de colaboración online, y me llamó la atención ver como muchas organizaciones seguían atrapadas en el caos de las bandejas de entrada con miles de correos y documentos repartidos por múltiples carpetas en máquinas locales o servidores, habiendo soluciones económicas y efectivas para evitar eso.&lt;p&gt;&lt;h4&gt;El Caos: situación típica en muchas pequeñas empresas&lt;/h4&gt;&lt;p&gt;Veamos un diálogo habitual en muchas PYMES (y no tan PYMES):&lt;br /&gt;&lt;br /&gt;  &lt;em&gt;(Yo):&lt;/em&gt; ¡Oye! ¿Cual es la contraseña para entrar en el servidor xxx del cliente yyy?&lt;br /&gt;&lt;br /&gt;  &lt;em&gt;(Lucas):&lt;/em&gt; Eso creo que lo tiene Juan en un correo.&lt;br /&gt;&lt;br /&gt;  &lt;em&gt;(Juan):&lt;/em&gt; No, a quién se lo enviaron es a Jose.&lt;br /&gt;&lt;br /&gt;  &lt;em&gt;(Jose abre su Outlook, realiza un rápido escaneo visual entre sus miles de correos):&lt;/em&gt; mmmm... no lo veo, espero que le doy a buscar.....&lt;br /&gt;&lt;br /&gt;  &lt;em&gt;(como es de esperar, el buscar del Outlook no encuentra absolutamente nada relacionado, o igual te dice que ha encontrado una impresora que si quieres instalar el driver metas un cd...)&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;  &lt;em&gt;(A Lucas se le enciende la bombilla):&lt;/em&gt; ¡espera! ¿no estará en el documento de claves que tenemos en el servidor?.&lt;br /&gt;&lt;br /&gt;  &lt;/p&gt;  &lt;p&gt;Miro en el servidor y tras esperar un rato a que  conecte (este Windows 2xxx Server es más lento que...) veo un documento llamado claves ftp... a ver si está ahí..., no hubo suerte...&lt;/p&gt;  &lt;p&gt;...pero no voy a desanimarme, acabo de ver que hay una carpeta que se llama claves; entro ahí y veo varios ficheros de texto, pero tampoco se encuentra en ninguno de ellos...&lt;/p&gt;  &lt;p&gt;...mmmm.... subo en el árbol de directorios y me encuentro una carpeta con el nombre del proyecto de dicho cliente, entro pero ahí no hay nada realmente....&lt;/p&gt;  &lt;p&gt;...y a todo esto ya ha pasado media hora para poder subir un pequeño fichero &lt;strong&gt;(y aún no he conseguido hacerlo)&lt;/strong&gt;, !acción que no debería haberme llevado más de un par de minutos!&lt;/p&gt;&lt;h4&gt;Problemas de repartir la información en un montón de archivos dispersos&lt;/h4&gt;&lt;p&gt;Tener la información que necesitas dispersa entre ficheros alojados en diversas carpetas de un servidor no es la mejor manera de organizarla. Es más dificil encontrarla, bien porque no sabes donde está, bien por los diversos formatos en los que se puede encontrar, y sobre todo por el hecho de que tampoco dispongas de una herramienta de búsqueda eficaz de la información contenida en esos ficheros. Hay que advertir a los usuarios de Windows que un perro de verdad tiene más probabilidades de encontrar algo olisqueando la carcasa de tu disco duro que el perrito del windows xp.&lt;/p&gt;&lt;p&gt;Si el servidor donde reside la información no es accesible desde el exterior, olvídate del teletrabajo en esos días de lluvia. O si no están en un servidor, sino en el ordenador de ese compañero de trabajo que se ha ido de vacaciones un mes a Brasil y nadie conoce su contraseña...bueno, lo puedes imaginar.&lt;/p&gt;&lt;h4&gt;Problemas de tener la información dispersa en un puñado de emails&lt;/h4&gt;&lt;p&gt;Si vas intercambiando emails con distintas personas a lo largo del proyecto, y además tu cliente de correo no es muy bueno con las búsquedas, y como suele pasar no has estado fino a la hora de escribir el asunto de los emails, buscar cualquier información puede ser una ardua tarea. Si además entran personas posteriormente al proyecto, hay que estar buscando los emails con información relevante para enviarselos y ponerlo al día.&lt;/p&gt;&lt;p&gt;Al final la información anda dispersa en las bandejas de correo de varias personas y encontrar cualquier pedacito de información no es tarea fácil.&lt;/p&gt;&lt;h4&gt;El Orden: usa alguna herramienta de colaboración online&lt;/h4&gt;&lt;p&gt;Existen multitud de herramientas de gestión de proyectos y colaboración online, bien como software instalable, bien como servicios ofrecidos por lo general gratis, con opciones ampliadas para clientes de pago e incluso suelen existir servicios de hosting para las soluciones instalables, por si no tenemos servidor o no queremos complicarnos la vida. Voy a hablar únicamente de los que he tenido la ocasión de usar o probar, pero basta googlear un poco para descubrir un vastísimo ecosistema de aplicaciones de este tipo.&lt;/p&gt;&lt;p&gt;Dentro de las instalables, mencionar dos clásicos: el &lt;a href="http://sourceforge.net/projects/dotproject/" title="Pulsa para acceder a la página del proyecto"&gt;dotProject&lt;/a&gt; y el &lt;a href="http://www.phprojekt.com/" title="Pulsa para acceder a la página del proyecto"&gt;PHProject 6&lt;/a&gt;. Ambos son soluciones en PHP, OpenSource, que podemos instalar o buscar algún proveedor que ofrezca el alojamiento de alguna de estas soluciones ya instaladas. No están mal si eres fan de las cosas rígidas y el Microsoft Project; para proyectos bajo el paraguas de cualquier combinación de metodologías ágiles (donde el énfasis está en la comunicación y no en rellenar formularios de tareas) son demasiado engorrosos. Lo he visto instalar en dos o tres empresas por las que he pasado y en ninguna se llegó a usar realmente ni sirvió para nada (bueno si, para complicarnos un poco más el trabajo).&lt;/p&gt;&lt;p&gt;Como servicios alojados hay muchos donde elegir, los que más he usado son &lt;a href="http://www.5pmweb.com/"&gt;5pm&lt;/a&gt;, &lt;a href="http://www.pivotaltracker.com/"&gt;Pivotal Tracker&lt;/a&gt; y por último &lt;a href="http://basecamphq.com/"&gt;Basecamp&lt;/a&gt;, sin duda de los mejores existentes hoy en día.&lt;/p&gt;&lt;p&gt;Por último mencionar soluciones que se ofrecen como servicio alojado para los que no disponen de servidor propio o no quieren complicarse la vida, pero a su vez su código fuente está disponible para instalarlo en nuestro propio servidor: &lt;a href="http://www.clockingit.com/"&gt;ClockingIT&lt;/a&gt;, cuyo código fuente podemos &lt;a href="http://github.com/ari/clockingit" title="Pulsa para acceder al código fuente del ClockingIT en Github"&gt;descargar&lt;/a&gt;, y la que para mi es mejor en esta categoría, &lt;a href="http://teambox.com/"&gt;Teambox&lt;/a&gt;, programada en Rails igual que la anterior aunque para mi gusto &lt;a href="https://github.com/teambox/teambox" title="Pulsa para acceder al código fuente del Teambox en Github"&gt;con un código&lt;/a&gt; de mucha más calidad.&lt;/p&gt;&lt;h4&gt;Conclusiones&lt;/h4&gt;&lt;p&gt;Hay un amplio espectro de soluciones sencillas de utilizar para organizar mejor la comunicación y los flujos de trabajo en la empresa. ¿Por qué seguir en el caos? En próximos artículos comentaré mi experiencia de uso con algunas de estas herramientas.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-4235490037339703720?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/4235490037339703720/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/12/herramientas-de-colaboracion-online-i.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4235490037339703720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4235490037339703720'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/12/herramientas-de-colaboracion-online-i.html' title='Herramientas de colaboración online (I)'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-2413122757230212073</id><published>2010-11-08T16:13:00.000Z</published><updated>2010-11-08T16:13:13.535Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='desarrollo'/><category scheme='http://www.blogger.com/atom/ns#' term='gitosis'/><category scheme='http://www.blogger.com/atom/ns#' term='cvs'/><title type='text'>Configurar un servidor Git usando Gitosis</title><content type='html'>&lt;p&gt;Tras un tiempo usando git en local contra un repositorio central subversion, es hora de migrar completamente y montar un servidor central de repositorios git utilizando Gitosis. Sigue leyendo para ver como hacerlo en un servidor Linux basado en la Ubuntu, aunque estas instrucciones son fácilmente adaptables a cualquier distro o Mac OS X.&lt;/p&gt;&lt;h4&gt;Instalando lo necesario&lt;/h4&gt;&lt;p&gt;Para su instalación, el servidor debe tener instalado el python y un paquete del &lt;acronym title="Python Enterprise Application Kit"&gt;PEAK&lt;/acronym&gt; llamado &lt;a href="http://peak.telecommunity.com/DevCenter/EasyInstall"&gt;EasyInstall&lt;/a&gt;. Para comprobar que tenemos ambos instalados hay que ejecutar desde la consola:&lt;/p&gt;&lt;code&gt;python --version&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El sistema debe responder con la versión instalada. Normalmente, en una distribución Ubuntu viene instalado por defecto. Para comprobar la disponibilidad del EasyInstall, se puede ejecutar:&lt;/p&gt;&lt;code&gt;python -c "import setuptools"&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El sistema responderá con una línea en blanco si está instalado y con un &lt;em&gt;ImportError: No module named setuptools&lt;/em&gt; si no se encuentra disponible. Por defecto, en una Ubuntu no viene instalado, por lo que habrá que hacerlo.&lt;/p&gt;&lt;p&gt;Lo primero es &lt;a href="http://pypi.python.org/pypi/setuptools#downloads" title="Pulsa para acceder a la página de descarga"&gt;descargarlo en nuestro servidor&lt;/a&gt;; en la página de descarga hay que elegir el fichero .egg correspondiente a la versión de Python que esté instalada en el servidor. En mi distro, ésta versión es la 2.6.5, por lo que descargo el fichero cuyo nombre acaba en &lt;em&gt;-py2.6.egg&lt;/em&gt;. Una vez descargado, lo instalo en la localización por defecto para los paquetes de Python. Para ello solo hay que hacer:&lt;/p&gt;&lt;code&gt;wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg&lt;/code&gt;&lt;br /&gt;&lt;code&gt;sudo sh setuptools-0.6c11-py2.6.egg&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Instalar Gitosis&lt;/h4&gt;&lt;p&gt;Para instalarlo, hay que descargar el código fuente de la aplicación desde su repositorio git y ejecutar el script de instalación. Se puede realizar desde nuestra carpeta de usuario en el servidor donde realizamos la instalación:&lt;/p&gt;&lt;code&gt;git clone git://eagain.net/gitosis&lt;/code&gt;&lt;br /&gt;&lt;code&gt;cd gitosis&lt;/code&gt;&lt;br /&gt;&lt;code&gt;sudo python setup.py install&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Crear clave de autentificación para el administrador del repositorio&lt;/h4&gt;&lt;p&gt;La autentificación ante el servidor no se realiza con contraseña, sino usando el esquema de clave pública/privada RSA. Asumo que ya el usuario dispone de una clave de este tipo, sino se puede generar fácilmente con el comando:&lt;/p&gt;&lt;code&gt;ssh-keygen -t rsa&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Hay que copiar el fichero de clave pública, normalmente situado en nuestra carpeta (de nuestra estación de trabajo, no el servidor) &lt;em&gt;/home/&amp;lt;nombre de usuario&gt;/.ssh/id_rsa.pub&lt;/em&gt; al servidor.&lt;/p&gt;&lt;h4&gt;Configurando el servidor para utilizar Gitosis&lt;/h4&gt;&lt;p&gt;Se requieren dos cosas para funcionar en el servidor: un usuario bajo el cual se ejecuta, y una carpeta donde almacenar los repositorios. Por convención se suele utilizar el usuario &lt;em&gt;git&lt;/em&gt;, y la carpeta &lt;em&gt;/srv/&amp;lt;midominio.com&gt;/git&lt;/em&gt;, pero se puede instalar donde se quiera. Yo voy a utilizar la carpeta &lt;em&gt;/var/git&lt;/em&gt;, por lo que ejecuto:&lt;/p&gt;&lt;code&gt;sudo adduser --shell /bin/sh --disabled-password --home /var/git git&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Inicializando Gitosis&lt;/h4&gt;&lt;p&gt;Para esto se usa un programa que viene con el gitosis, &lt;em&gt;gitosis-init&lt;/em&gt;, el cual se ejecutará usando el usuario creado previamente. En este punto hay que recordar donde guardamos nuestra clave pública para indicárselo a dicho script.&lt;/p&gt;&lt;code&gt;sudo -H -u git gitosis-init &amp;lt; /ruta hacia nuestro/id_rsa.pub&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Tras esto hay que realizar un pequeño fix para que podamos crear repositorios adicionales.&lt;/p&gt;&lt;code&gt;sudo chmod 755 /var/git/repositories/gitosis-admin.git/hooks/post-update&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Hay que recordar cambiar /var/git por la ruta hacia la carpeta home que decidimos en su momento.&lt;/p&gt;&lt;h4&gt;Configurando Gitosis&lt;/h4&gt;&lt;p&gt;La configuración de esta aplicación se trata como un repositorio git. Debemos clonarlo en nuestra estación de trabajo (aquella desde la que copiamos nuestro id_rsa.pub), realizar los cambios necesarios y subir las modificaciones al servidor.&lt;/p&gt;&lt;code&gt;git clone git@dominio_de_nuestro_servidor.com:gitosis-admin.git&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Accedemos a la carpeta local donde está la configuración y vemos un fichero de texto, &lt;em&gt;gitosis.conf&lt;/em&gt;, y una carpeta, &lt;em&gt;keydir&lt;/em&gt;, donde se halla una copia de nuestra clave pública, que es la que se usa actualmente para autentificar el servidor.&lt;/p&gt;&lt;p&gt;En esta carpeta se añadirán las claves públicas de las personas que deban acceder al repositorio, y en el fichero de configuración es donde se añaden los repositorios que se vayan creando y se establece el acceso de las personas a ellos. Incialmente este fichero tendrá esta pinta:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;[gitosis]&lt;br /&gt;&lt;br /&gt;[group gitosis-admin]&lt;br /&gt;writable = gitosis-admin&lt;br /&gt;members = ejosafat@nombre_de_mi_maquina.local&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Esto significa que existe un grupo denominado &lt;em&gt;gitosis-admin&lt;/em&gt;, con permiso de escritura en el repositorio del mismo nombre, y del que son miembros las personas especificadas en la línea members, donde separados por un espacio se indican los nombres de los ficheros de clave pública presentes en keydir cuyos usuarios pueden acceder al repositorio en cuestión.&lt;/p&gt;&lt;p&gt;Los cambios que se realizen como la adición de claves a la carpeta keydir o la información de configuración en el fichero se suben al servidor central utilizando el comando git push (tras haber realizado el git commit correspondiente en la versión local.)&lt;/p&gt;&lt;p&gt;De hecho el primer cambio que realizo es cambiar el nombre del fichero de claves para dejarlo en algo tan sencillo como ejosafat.pub, por lo que la configuración de los miembros administrativos, quedaría como:&lt;/p&gt;&lt;code&gt;members = ejosafat&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Añadir nuevos repositorios&lt;/h4&gt;&lt;p&gt;Para añadir nuestros repositorios, lo único que hay que hacer es crear la entrada correspondiente en el fichero gitosis.conf. Por ejemplo:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;[group mi_proyecto]&lt;br /&gt;writable = mi_proyecto&lt;br /&gt;members = ejosafat juan pepe&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Si queremos añadir usuarios con acceso de solo lectura, creamos otro grupo y utilizamos la directiva readable.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;[group mi_proyecto_readonly]&lt;br /&gt;readable = mi_proyecto&lt;br /&gt;members = marcos lucas&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Hay que recordar que cada vez que añadimos un usuario nuevo hay que añadir una copia de su clave pública a la carpeta &lt;em&gt;keydir&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Una vez hemos hecho el commit y el push, el nuevo repositorio se creará en el servidor. Si ya existía un repositorio local con el código, nos vamos a la carpeta donde se encuentra y hacemos un:&lt;/p&gt;&lt;code&gt;git remote add origin git@dominio_de_nuestro_servidor.com:mi_proyecto&lt;/code&gt;&lt;br /&gt;&lt;code&gt;git push origin master&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Si no existía ningun repositorio previo, podemos crear uno utilizando &lt;em&gt;git init&lt;/em&gt;.&lt;/p&gt;&lt;h4&gt;Notas sobre puertos ssh&lt;/h4&gt;&lt;p&gt;Si nuestro servidor usa un puerto distinto del 22 para las conexiones SSH, debemos especificarlos en nuestra fichero ~/.ssh/config, de la forma:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;Host dominio_de_nuestro_servidor.com&lt;br /&gt;Port 1234&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Conclusiones&lt;/h4&gt;&lt;p&gt;Tras un tiempo de transición utilizando git contra un servidor subversion, es recomendable dar el salto definitivo para gestionar enteramente tus versiones con Git, tanto en local como en el servidor remoto. Créeme, lo agradecerás a la hora de trabajar con branches de desarrollo, algo muy importante tal &lt;a href="http://eddyjosafat.blogspot.com/2010/10/desarrollo-estable-usar-branches-con.html"&gt;como hablé en otro artículo&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-2413122757230212073?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/2413122757230212073/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/11/configurar-un-servidor-git-usando.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/2413122757230212073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/2413122757230212073'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/11/configurar-un-servidor-git-usando.html' title='Configurar un servidor Git usando Gitosis'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-3799995260743126933</id><published>2010-10-11T16:29:00.001+01:00</published><updated>2010-10-13T16:05:14.113+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='desarrollo'/><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><title type='text'>Desarrollo estable - usar branches con git</title><content type='html'>&lt;p&gt;En la típica aplicación de internet ya desplegada en servidor(es) de producción, lo habitual en un momento dado es trabajar en solucionar los bugs que el cliente va detectando por un lado, y por el otro ir añadiendo nuevas funcionalidades que se van produciendo.&lt;/p&gt;&lt;p&gt;¿Qué pasa cuando estoy trabajando en una nueva funcionalidad, tengo la mitad de los ficheros de la aplicación modificados pero el cambio aún no está completo, y de repente surge un bug que hay que solucionar para ayer? Si hago las correcciones oportunas y desplego la aplicación en el estado actual (con una serie de cambios en otras áreas a mitad) es posible que el sistema deje de funcionar.&lt;/p&gt;&lt;p&gt;Eso me ha pasado alguna vez, pero afortunadamente es historia con un uso disciplinado de las ramas (branches) de desarrollo que ofrecen por lo general todos los sistemas de control de versiones.&lt;/p&gt;&lt;h4&gt;Creación de branches en Git&lt;/h4&gt;&lt;p&gt;A la hora de trabajar en una funcionalidad nueva, en lugar de hacerlo directamente sobre la rama principal de desarrollo, creo una rama nueva dedicada única y exclusivamente a esta funcionalidad. El comando para ello es:&lt;/p&gt;&lt;code&gt;git checkout -b nueva_funcionalidad&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Este comando es un 2 en 1: crea una nueva rama con el nombre indicado y además hace un checkout de ésta, por lo que en este momento estaremos trabajando en la rama y no en la línea principal de desarrollo (en el git se llama &lt;em&gt;master&lt;/em&gt;).&lt;/p&gt;&lt;p&gt;¿Qué queremos volver a trabajar en la rama principal para corregir un bug?&lt;/p&gt;&lt;code&gt;git checkout master&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Si tenemos cambios sin commitear en la rama actual no nos dejará hacer el checkout, o bien los commiteamos o descargamos la rama principal en otra carpeta. De esta manera siempre mantendremos la línea principal de desarrollo estable mientras trabajamos en la nueva funcionalidad.&lt;/p&gt;&lt;h4&gt;Fusionar&lt;/h4&gt;&lt;p&gt;Una vez hemos terminado de programar la funcionalidad y nos hemos asegurado que pasa todos los tests (los nuevos específicos y los existentes), es hora de agregar nuestros cambios a la rama principal de desarrollo. Para ello debemos fusionarlas. Esto lo hacemos cambiando nuestra versión de trabajo a la rama principal y luego pedir la fusión:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  git checkout master&lt;br /&gt;  git merge nueva_funcionalidad&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Existen alternativas para especificar exactamente que commits de la rama nueva_funcionalidad fusionamos, pero a no ser que estemos trabajando en algo muy gordo que queramos ir añadiendo por partes lo usaremos rara vez, por lo que no detallaré esas otras alternativas.&lt;/p&gt;&lt;p&gt;Y si ya hemos acabado de trabajar en la rama de desarrollo, llegó el momento de borrarla. Tras el paso anterior donde hicimos la fusión, podemos hacer:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  git branch -d nueva_funcionalidad&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Si no hemos hecho fusión ni nada o se queja de algo, cambiamos el switch -d por -D y listo.&lt;/p&gt;&lt;h4&gt;Tags&lt;/h4&gt;&lt;p&gt;Tanto si usas alguna metodología ágil como si no, cada cierto tiempo harás un "release" de tu código, es decir, sacarás una nueva versión o desplegarás los resultados de una iteración en tu servidor.&lt;/p&gt;&lt;p&gt;En un momento dado, como saber que versión de tu código está desplegada en el servidor sin comparar fichero a fichero o mirar fechas tanto de los commits como de los ficheros desplegados para averiguarlo? Tags al rescate.&lt;/p&gt;&lt;p&gt;Cuando vayamos a hacer un despliegue en servidor, podemos marcar el código en su estado actual con una etiqueta (versión 1.1, iteración 2, release 20100613...). Los tags a diferencia de los branches no permiten modificaciones, con lo cual si en un momento dado hacemos un checkout de un tag no podremos commitear ningún cambio que hagamos, pero siempre podremos crear una rama a partir de dicho código. El comando para crear tags es:&lt;/p&gt;&lt;code&gt;git tag "version 1.1"&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;&lt;p&gt;La práctica de trabajar con ramas de desarrollo ha disminuido el número de situaciones incómodas en mi vida diaria como programador y no supone un esfuerzo extra en el trabajo, así que ¡no hay ninguna razón para que no las estés usando!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-3799995260743126933?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/3799995260743126933/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/10/desarrollo-estable-usar-branches-con.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3799995260743126933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3799995260743126933'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/10/desarrollo-estable-usar-branches-con.html' title='Desarrollo estable - usar branches con git'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-5140556260829956829</id><published>2010-09-13T16:54:00.002+01:00</published><updated>2010-09-13T16:54:34.972+01:00</updated><title type='text'>Vuelta de las vacaciones</title><content type='html'>Ya de vuelta de las vacaciones, e inspirado por la peregrinación a Santiago de Compostela, en breve reanudaré la publicación de artículos. ¡No te los pierdas!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-5140556260829956829?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/5140556260829956829/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/09/vuelta-de-las-vacaciones.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/5140556260829956829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/5140556260829956829'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/09/vuelta-de-las-vacaciones.html' title='Vuelta de las vacaciones'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-8141638277462859009</id><published>2010-08-02T15:11:00.000+01:00</published><updated>2010-08-02T15:11:26.784+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Utilizar Git con Subversion</title><content type='html'>&lt;p&gt;Inicialmente implantamos el uso de Subversion en la empresa porque habían varias personas ya familiarizadas con él y era la única opción que nos ofrecía Dreamhost.&lt;/p&gt;&lt;p&gt;Sin embargo el Subversion presenta algunos problemillas e ineficiencias por las cuales yo personalmente uso &lt;a href="http://git-scm.com/" title="Página del proyecto"&gt;Git&lt;/a&gt; en mi máquina, dado que permite conectar con repositorios subversion sin problemas, manteniendo a nivel local todas las ventajas que me ofrece el &lt;a href="http://git-scm.com/" title="Página del proyecto"&gt;Git&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Y aunque vamos a migrar enteramente a Git próximamente, entretanto trabajaremos con él localmente, mientras seguimos usando como repositorio central el Subversion de Dreamhost.&lt;/p&gt;&lt;h4&gt;¿Por qué Git?&lt;/h4&gt;&lt;li&gt;El uso de este sistema de control de versiones cada vez está más extendido, sobre todo en el mundo del OpenSource. Cada vez más proyectos están alojados en &lt;a href="http://github.com/" title="Página princial de github"&gt;Github&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Es mucho más cómodo de usar incluso desde una consola de comandos. Y más listo: se acabó el dar ordenes explícitas con comandos subversion para borrar o mover archivos; podemos realizar esas operaciones con normalidad desde nuestra interfaz preferida, que Git se da cuenta por si mismo de que lo has hecho. Crear ramas (branches) se vuelve mucho más fácil también y menos costoso en espacio de almacenamiento.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Mayor control sobre los cambios realizados, pudiendo especificar con exactitud que cambios se suben al repositorio principal y cuales no, incluso dentro de un mismo fichero.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Git está pensado para entornos de trabajo altamente distribuidos, por lo que el repositorio reside en nuestra propia máquina, pudiendo trabajar sin necesidad de conectarnos al repositorio central, al que subiremos los cambios cuando los tengamos pulidos (y posiblemente seamos autorizados por alguien que supervise dichas operaciones), o nos conectaremos para pillar los cambios que hayan subido los otros.&lt;/li&gt;&lt;br /&gt;&lt;h4&gt;Instalación de Git&lt;/h4&gt;&lt;h5&gt;Mac OS X&lt;/h5&gt;&lt;p&gt;Desde la sección de descargas de la página, existe un &lt;a href="http://code.google.com/p/git-osx-installer/downloads/list?can=3" title="Acceder a la descarga de la versión para Mac del Git"&gt;enlace&lt;/a&gt; para la versión instalable para Mac (Leopard). Instalar como cualquier aplicación de Mac.&lt;/p&gt;&lt;p&gt;Aunque el git viene por defecto con el &lt;em&gt;gitk&lt;/em&gt; y &lt;em&gt;git-gui&lt;/em&gt; como herramientas gráficas, en el Mac podemos también &lt;a href="http://gitx.frim.nl/"&gt;descargar el GitX&lt;/a&gt;&lt;/p&gt;&lt;h5&gt;Linux (Ubuntu)&lt;/h5&gt;&lt;p&gt;En Ubuntu, hay que instalar los paquetes &lt;em&gt;git-core&lt;/em&gt;, &lt;em&gt;git-svn&lt;/em&gt; y para asegurarnos que no hay errores, &lt;em&gt;subversion-perl&lt;/em&gt;.&lt;/p&gt;&lt;h5&gt;Windows (XP)&lt;/h5&gt;&lt;p&gt;Hay varias formas de instalarlo, quizás la más sencilla sea &lt;a href="http://code.google.com/p/msysgit/downloads/list"&gt;descargar e instalar msysgit.&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Una vez descargado, tras el doble click pertinente para ejecutar el instalador y un par de pulsaciones en el botón Next para avanzar, llegamos a la selección de componentes para la instalación. Allí marcar un botón que dice &lt;em&gt;Conext menu entries&lt;/em&gt; y luego otra vez &lt;em&gt;Next&lt;/em&gt;. Cuando lleguemos a otra pantalla donde se nos dan más opciones a elegir, seleccionar &lt;em&gt;Run Git from the Windows Command Prompt&lt;/em&gt;. La siguiente opción se deja como está (Checkout Windows-style, commit Unix-....).&lt;/p&gt;&lt;p&gt;Para usarlo, en el explorador de archivos pulsamos con botón derecho sobre la carpeta en la que queramos volcar nuestros repositorios, y seleccionamos la opción git bash here.&lt;/p&gt;&lt;h4&gt;Trabajar con Git contra un repositorio central Subversion&lt;/h4&gt;&lt;p&gt;Hablaré de las tres operaciones básicas a realizar, a saber: el checkout inicial del proyecto detro de una carpeta administrada por git, los commit tanto a nuestro repositorio local como al central (en Subversion), y las operaciones de actualización de nuestra copia con los últimos cambios subidos por nuestros compañeros de equipo.&lt;/p&gt;&lt;p&gt;Usaré la interfaz de línea de comandos para realizar dichas operaciones habituales.&lt;/p&gt;&lt;h5&gt;Checkout&lt;/h5&gt;&lt;p&gt;Si hemos creado el repositorio subversion con la estructura clásica (trunk, branches, tags), basta con hacer:&lt;/p&gt;&lt;code&gt;git svn clone --prefix svn/ -s http://direcciondemirepositorio.com/nombre_de_proyecto&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Esto crea una carpeta denominada nombre_de_proyecto, en la cual se van a volcar todos los cambios realizados en el repositorio central hasta ese momento, preservando por tanto el historial.&lt;/p&gt;&lt;h5&gt;Commit&lt;/h5&gt;&lt;p&gt;En Subversion, cuando hacemos commit desde una carpeta y sin especificar ficheros concretos, sube todos los cambios que hayan presentes. La filosofía de Git es distinta: primero decimos que ficheros (o cambios dentro de ficheros) queremos meter en el próximo commit (&lt;em&gt;git add -i&lt;/em&gt; para acceder a una herramienta interactiva donde indicar lo que queremos meter), y luego realizamos el commit propiamente dicho.&lt;/p&gt;&lt;p&gt;Ojo que en el Git cuando se hace un commit, se hace en el repositorio local. Cuando queramos subir los commit realizados al repositorio subversion, usaremos &lt;em&gt;git svn dcommit&lt;/em&gt;&lt;/p&gt;&lt;h5&gt;Update&lt;/h5&gt;&lt;p&gt;Para actualizar hay dos maneras de hacerlo, una es bajar los cambios y después fusionarlos, y la segunda es una fusión de ambas y por tanto la más usada:&lt;/p&gt;&lt;code&gt;git svn rebase&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Conclusiones&lt;/h4&gt;&lt;p&gt;Aunque el git tiene sus detractores, y ya he leído varios artículos de gente que se iba a pasar al Mercurial, yo me siento mucho más cómodo con él que con el Subversion.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-8141638277462859009?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/8141638277462859009/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/08/utilizar-git-con-subversion.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/8141638277462859009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/8141638277462859009'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/08/utilizar-git-con-subversion.html' title='Utilizar Git con Subversion'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-5436812650196758203</id><published>2010-07-02T14:38:00.000+01:00</published><updated>2010-07-02T14:38:12.796+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='proceso'/><category scheme='http://www.blogger.com/atom/ns#' term='cliente'/><title type='text'>Tratar con el cliente</title><content type='html'>&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;En el &lt;a href="http://eddyjosafat.blogspot.com/2009/12/arrancando.html"&gt;primer artículo de este blog&lt;/a&gt; hablé de la situación que me encontré al llegar a la empresa con la que colaboro principalmente en la actualidad, donde seguían el típico workflow de trabajo en la típica empresa que se dedica a hacer las típicas páginas web, es decir, caos y más caos.&lt;/p&gt;&lt;p&gt;Tras hacer un diagnóstico inicial confeccioné una lista de medidas a tomar (&lt;a href="http://eddyjosafat.blogspot.com/2009/12/arrancando.html#objetivos"&gt;ver lista de medidas&lt;/a&gt;). La mayor parte de aquellos puntos están cumplidos, otros aún están en desarrollo. Hoy me voy a centrar en uno de ellos, quizás de los más difíciles de solucionar: &lt;strong&gt;la relación con el cliente&lt;/strong&gt;.&lt;/p&gt;&lt;h4&gt;Los problemas de siempre&lt;/h4&gt;&lt;ul&gt;  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Interrupciones:&lt;/strong&gt; estás trabajando concentrado en un proyecto, cuando te piden que lo dejes todo de lado porque hay que arreglar no se qué en cualquier otro proyecto. Lo haces, vuelves al principal y vuelven a cortarte para decirte que hay que hacer no se qué en otro. Y así continuamente.&lt;/p&gt;    &lt;p&gt;La neurociencia ha avanzado muchísimo en los últimos años, y se sabe muchas cosas de como funciona el cerebro, ya no es algo tan misterioso como nos decían de niños. Y una cosa que se sabe es que el contexto es fundamental. Tardamos entre 20 y 30 minutos en meternos de lleno en el contexto de una tarea compleja, una vez lo hemos alcanzado y además profundizamos en ese estado mental nuestro rendimiento es el máximo. Una simple interrupción de 1 minuto no es perder tan solo ese tiempo en la tarea, es perder todo el tiempo que invertimos en alcanzar ese punto de contexto.&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;&lt;p&gt;&lt;strong&gt;¡Esto es urgente!&lt;/strong&gt; Vale, eso me lo creo, pero....¿es prioritario? Ambos términos suelen confundirse por norma general.&lt;/p&gt;    &lt;p&gt;Siempre se olvida que la urgencia del cliente no tiene porque ser nuestra prioridad. Para mi el sentido de lo urgente es directamente proporcional a cuánto facturas de media en un año a ese cliente.&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Dejarte impresionar por los gritos del cliente&lt;/strong&gt;. Muy relacionado con el punto anterior, suele pasar que un cliente enojado o nervioso porque quiere que tal o cual funcionalidad se implemente ya (olvidando que nos lo habían pedido el día anterior o incluso ese mismo día)&lt;/p&gt;    &lt;p&gt;Yo personalmente llevo tantos años de jefe de proyecto que ya me he inmunizado a gritos y amenazas, pero esto no sucede siempre con tus jefes, los cuales llegan corriendo para que dejes el proyecto de cien mil euros en el que estás trabajando y añadas un formulario de contacto a la web de mierda del cliente que ha pagado mil, solo porque han estado chillándoles al teléfono. Y los que menos pagan suelen ser los más que chillan. A veces entran ganas de recordar mis tiempos de artes marciales y soltar algún ¡kiai! bien fuerte y profundo para amedrentarlos.&lt;/p&gt;&lt;/li&gt;    &lt;li&gt;&lt;p&gt;&lt;strong&gt;Presupuestos cerrados:&lt;/strong&gt; esto es lo de siempre. El cliente llega con una idea más o menos difusa, con un listado de características que no se sabe muy bien para que lo quiere, si lo usarán o no, etc... pero hay que entregar un presupuesto cerrado, con tiempos definidos.&lt;/p&gt;      &lt;p&gt;Y todos sabemos que el cliente no sabrá realmente lo que quiere o lo que necesita a medida que lo vayamos descubriendo juntos desarrollando y probando el proyecto, pero para entonces por lo general nos habremos pasado de tiempo y presupuesto, viendo como se reduce el margen de beneficios gradualmente hasta llegar a 0 o negativo en el peor de los casos, que además pasa de cuando en cuando.&lt;/p&gt;      &lt;p&gt;Y como no, el coste oculto de las modificaciones a posteriori. El cliente viene, encarga proyecto, lo hacemos, y esperamos por su feedback y validación de lo hecho durante meses. Tras ese tiempo vuelve a interesarse por el proyecto y pretende que hagamos todos los cambios que nos pide, que aunque previstos en el presupuesto inicial, hacerlos después de 3 meses de haber terminado de programar supone volver a perder tiempo metiéndonos en el contexto del proyecto y además parar aquello en lo que estemos trabajando en ese momento.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Vias de resolución&lt;/h4&gt;&lt;ul&gt;  &lt;li&gt;Respecto a las interrupciones, he tomado varias medidas:&lt;br /&gt;    &lt;ul&gt;      &lt;li&gt;Eliminar el teléfono de la mesa de trabajo. Para gran sorpresa de todos una mañana llegué al trabajo y con gestos enérgicos tiré del cable que lo conectaba al PTR y metí el teléfono en un armario perdido lejos de mí. La comunicación telefónica es altamente disruptiva, cuando un cliente quiere hablar directamente conmigo o me manda un email o deja recado y yo lo llamaré cuando a mí me venga bien, en el tiempo entre tareas. El mejor momento para el cliente de hablar no coincide por lo general con el mejor momento para mi. Entre yo y el cliente, ganan mis preferencias y mi productividad.&lt;/li&gt;      &lt;li&gt;Con los compañeros he desarrollado un código: si tengo los auriculares puestos, quiere decir que estoy en momento de máxima concentración. Esa duda o ese chiste me lo puedes contar cuando esté realizando otro tipo de tarea (leer correo, blogs, mientras voy camino del baño...)&lt;/li&gt;      &lt;li&gt;Facturarle al cliente el coste de las interrupciones. Teníamos un cliente que nos pedía cambios urgentes todos los días. Alguno de esos cambios en sí no llevaban más de 10 minutos, pero le facturábamos la hora entera. Nuestro interlocutor en el cliente era informático, y cuando arguyó que dicho cambio no llevaba una hora entera le expliqué que para hacer ese cambio debía cortar la tarea que estaba haciendo, meterme en el contexto de su proyecto, hacer el cambio, probar que va bien, hablar con él por teléfono para aclaraciones, subir al servidor de pruebas, esperar su confirmación, subirlo a producción, y tiempo para volver a meterme en el contexto de la tarea que interrumpí para atenderle a él. &lt;strong&gt;Lo entendió&lt;/strong&gt;, y nunca más cuestionó los tiempos facturados.&lt;/li&gt;    &lt;/ul&gt;  &lt;/li&gt;  &lt;li&gt;¡Esto es urgente!, ante ese grito del cliente que pone nervioso a tu jefe el cual viene a tu mesa pidiendo que deje todo lo que estás haciendo porque hay que satisfacerle y total son 10 minutos.... ¿qué hacer ante esto? pues lo mismo que con las interrupciones, educar al cliente y hacerle ver tanto a él como a tu jefe los costes. Yo uso un par de ejemplos extraídos de como funcionan otros sectores (y de los que nadie se queja y todo el mundo da por hecho que funciona así):&lt;br /&gt;    &lt;ul&gt;      &lt;li&gt;&lt;strong&gt;El ejemplo del taller de coches:&lt;/strong&gt; ¿Alguna vez han tratado de llevar el coche al taller y decirle al mecánico que es urgente y necesitan el coche en el mismo día? Respondo yo mismo: &lt;strong&gt;NO&lt;/strong&gt;. Si quieres que tu coche esté disponible para el fin de semana te asegurarás de preguntar desde el lunes en el taller, nunca se te ocurrirá llevarlo el viernes por la mañana. Igual si insistieras mucho y &lt;strong&gt;pagaras un pastón&lt;/strong&gt; conseguirías que te lo arreglaran en un día, eso si, si la reparación no dependiera de piezas de repuesto no disponibles en ese momento. ¿Por qué nos bajamos los pantalones de esa manera en nuestro sector? Hay que acostumbrar al cliente a que funcionamos como otros sectores, que más inteligentemente que nosotros han sabido defender su trabajo y su manera de hacer las cosas.&lt;/li&gt;      &lt;li&gt;&lt;strong&gt;El ejemplo del cortador de piedra:&lt;/strong&gt; &lt;p&gt;Una vez fui a una fábrica de piedra a media mañana para comprar una encimera de baño. Elegimos la pieza, preguntamos cuanto tardaban en cortarla a las medidas pedidas: hora y media. ¡Estupendo! pensamos, así que le dijimos que podíamos esperar por la zona y así podíamos llevarnosla a mediodía.&lt;/p&gt;&lt;p&gt;El señor dijo que imposible: sus operarios estaban en ese momento con una gran losa de piedra cada uno para cortar pertenecientes a otros encargos, y para atendernos tenían que dejar a medias lo que estaban haciendo, quitar la enorme piedra de su puesto de trabajo, poner la nuestra, ver lo que había que hacer, retirar la piedra, volver a poner la anterior y volver a recordar que es lo que había que hacer con ella.&lt;/p&gt;      &lt;p&gt;Conceptualmente, cuando estamos inmersos en un proyecto complejo donde tienes que manejar un universo de objetos y elementos interrelacionados en tu cabeza, parar tu trabajo para resolver esa pequeña urgencia es el equivalente de estar trabajando con una piedra del tamaño de una catedral y meterte en el follón de retirarla de tu mesa de trabajo, para poner la nueva piedra, y volver otra vez al follón de volver a colocar esa catedral para seguir trabajando con ella.&lt;/p&gt;&lt;/li&gt;    &lt;/ul&gt;  &lt;/li&gt;  &lt;li&gt;&lt;p&gt;Presupuestos cerrados que al final se salen de madre, como siempre. Este es el pan nuestro de cada día cuando desarrollas a medida para terceros, es lo más complejo de resolver, junto con el desinterés de algunos clientes por el proyecto hasta 3 meses más tarde de haberlo dado tú por finalizado.&lt;/p&gt;    &lt;p&gt;Respecto a lo primero, todos los últimos presupuestos que nos han pedido los hemos simplificado para ofrecer con un coste cerrado una serie de funcionalidades estrictamente definidas, explicándole al cliente que es mejor hacer algo básico que empiece a usar para que se de cuenta de lo que necesita realmente y a partir de ahí ir trabajando por iteraciones en las que se implementen poco a poco cosas que vaya demandando, facturando por horas. Así puede obtener justo lo que necesita controlando el dinero invertido en el proyecto.&lt;/p&gt;    &lt;p&gt;En cuanto a lo de no darte feedback o solicitarte cambios meses después de haberlo finalizado, la política es: mientras trabajamos en tu proyecto te notificamos semana a semana de su estado, con despliegue en servidor de pruebas para ir probando. Paralelamente se le va pidiendo todo el material que nos tenga que suministrar. Si una vez finalizado sigue sin resollar, para cuando lo haga se le pondrá en cola respecto a las tareas que haya en ese momento. Aqui lo bueno es cobrar una buena cantidad de anticipo antes de comenzar el proyecto para que el cliente muestre bastante interés en finalizarlo cuanto antes.&lt;/p&gt;    &lt;p&gt;Para esta última vía he desarrollado otro ejemplo, el de la &lt;strong&gt;compra/construcción de una casa.&lt;/strong&gt; Cuando compras una casa o contratas la obra, una vez comprada o finalizada la obra, no esperas 6 meses para decirle al promotor/constructor que la instalación del agua va mal, o que la calidad de los materiales no es la acordada, o lo que sea. Ten por seguro que esto lo hará todo el mundo en la primera semana, porque saben que si lo hacen después el promotor/constructor se hará el loco o tardará una eternidad en resolverlo.&lt;/p&gt;    &lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Conclusiones&lt;/h4&gt;&lt;p&gt;Implementando estas medidas hemos conseguido algo de mejoría, aunque la conclusión final es que lo mejor siempre es dedicarse a productos propios antes que en proyectos a medida (sobre todo para el típico cliente en Canarias). La empresa donde trabajo está tomando esa orientación, y a nivel personal yo tampoco hago ya nada a medida, solo trabajo en mis propios productos.&lt;/p&gt;&lt;p&gt;Hasta conseguir un producto exitoso habrá que seguir comiendo, como siempre, por lo aún habrá que aguantar clientes durante un tiempo y por tanto mejor educarlos lentamente. ¿A alguien se le ocurren más ejemplos didácticos? Espero oir los tuyos.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-5436812650196758203?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/5436812650196758203/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/07/tratar-con-el-cliente.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/5436812650196758203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/5436812650196758203'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/07/tratar-con-el-cliente.html' title='Tratar con el cliente'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-8776300813362924131</id><published>2010-06-17T15:11:00.003+01:00</published><updated>2010-06-21T14:58:00.832+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='servidor'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='script'/><title type='text'>Más scripts de apoyo</title><content type='html'>&lt;p&gt;Describiré brevemente en esta entrada una serie de scripts auxiliares que también me cree para apoyar toda la infraestructura de generación de un proyecto, pero sin entrar en detalles sobre el código. Este &lt;a href="http://rubyforge.org/projects/autom-proyectos/"&gt;lo puedes descargar del RubyForge&lt;/a&gt; y está documentado.&lt;/p&gt;&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;He mostrado los scripts que más nos alivian el trabajo a la hora de generar la infraestructura para un proyecto nuevo, tan solo queda automatizar pequeñas tareas asociadas. A continuación comento brevemente cada uno de ellos sin ahondar en explicaciones.&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;p&gt;Crear un conjunto de pequeños scripts para automatizar pequeñas tareas rutinarias. En concreto:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Al crear los servidores virtuales para todos los usuarios, el Apache se queja de las carpetas no existentes. Para evitar esto, se debe hacer un checkout inicial del proyecto para cada usuario en su carpeta /home.&lt;/li&gt;&lt;li&gt;Crear una o varias bases de datos MySQL necesarias para el proyecto.&lt;/li&gt;&lt;li&gt;En la carpeta /etc del servidor de desarrollo está la lista de proyectos, utilizada por otros scripts para realizar backups u otras operaciones. Hay que añadir una entrada en esta lista para cada nuevo proyecto.&lt;/li&gt;&lt;li&gt;Los repositorios subversion generalmente se estructuran en torno a 3 ramas principales, trunk, branch y tags. Crear esta estructura inicial.&lt;/li&gt;&lt;li&gt;Cuando se genera el código inicial de un proyecto, por ejemplo Rails, hay que se agregar al repositorio los ficheros generados, excepto aquellos que variarán para cada desarrollador (caché, logs, configuración de base de datos local).&lt;/li&gt;&lt;li&gt;A veces se necesita actualizar del repositorio los cambios introducidos en todos los proyectos para estar al día.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Automatización&lt;/h4&gt;&lt;h5&gt;checkout_proyectos.rb &amp;lt;nombre proyecto&gt;&lt;/h5&gt;&lt;p&gt;Este script hace un checkout del proyecto especificado como argumento en todas las carpetas de los usuarios del sistema, lista que lee del fichero de configuración. De esta manaera el Apache no se quejará cada vez que carga la configuración indicando que hay hosts virtuales en los que no encuentra la carpeta, ya que el script para crear estos hosts visto en otro artículo crea uno para cada usuario, aunque este no haya creado la carpeta para alojar el código&lt;/p&gt;&lt;h5&gt;crear_databases.rb &amp;lt;id de proyecto&gt; [tipo de proyecto] [password de mysql]&lt;/h5&gt;&lt;p&gt;Este script tiene como argumento obligatorio el nombre del proyecto, y como opcionales el tipo (php o rails) y la contraseña de root de mysql. Esto último argumento es opcional tan solo si no hay contraseña del usuario root de la base de datos. Ahorra un poco de tecleado o clicks a la hora de crear las bases de datos necesarias.&lt;/p&gt;&lt;h5&gt;crear_entrada_lista.rb &amp;lt;id de proyecto&gt;&lt;/h5&gt;&lt;p&gt;Este script añade automáticamente la entrada correspondiente a un nuevo proyecto en el fichero con la lista de proyectos.&lt;/p&gt;&lt;h5&gt;crear_estructura.rb &amp;lt;id de proyecto&gt; [nombre de usuario]&lt;/h5&gt;&lt;p&gt;Crea la estructura clásica de un proyecto en subversion (carpetas trunk, branch y tags)&lt;/p&gt;&lt;h5&gt;generar_proyecto_rails.rb &amp;lt;ruta a carpeta&gt;&lt;/h5&gt;&lt;p&gt;A la hora de crear un proyecto y añadirlo al repositorio, hay que ignorar los logs, los ficheros de tmp y demás. Además hay que copiar el fichero database.yml con otro nombre para que cada desarrollador utilice el adecuado para su configuración. Todo esto y más (borrar el index.html de public, por ejemplo), ya lo hace este script.&lt;/p&gt;&lt;h5&gt;update_projects.rb &amp;lt;usuario&gt; [ruta hacia fichero con lista de proyectos]&lt;/h5&gt;&lt;p&gt;Este lo uilizamos cuando queremos actualizar nuestra versión de todos los proyectos para estar al día.&lt;/p&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;&lt;p&gt;Haber invertido tiempo en estos scripts nos ha ahorrado bastante tiempo y aburrimiento en nuestro departamento de desarrollo,  y los utilizamos frecuentemente.&lt;/p&gt;&lt;p&gt;Sin embargo, recientemente he descubierto el &lt;a href="http://www.opscode.com/chef/"&gt;Chef&lt;/a&gt;, potente framework de integración de sistemas que permite mediante recetas creadas (Ruby) desplegar todo tipo de servidores y ajustar su configuración de manera totalmente automatizada y eficiente.&lt;/p&gt;&lt;p&gt;Por otro lado me he pasado al &lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; como sistema de control de versiones, mucho más eficiente y cómodo que el Subversion.&lt;/p&gt;&lt;p&gt;Ya hablaré de todo esto más adelante, en próximos artículos voy a tratar un poco más de la parte humana de la automatización y la eficiencia.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-8776300813362924131?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/8776300813362924131/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/06/mas-scripts-de-apoyo.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/8776300813362924131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/8776300813362924131'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/06/mas-scripts-de-apoyo.html' title='Más scripts de apoyo'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-4774863419750661355</id><published>2010-05-19T12:44:00.000+01:00</published><updated>2010-05-19T12:44:07.356+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dns apache virtual_host ruby'/><title type='text'>Creación de servidores virtuales (II)</title><content type='html'>&lt;p&gt;Segunda parte del script de automatización de la creación de servidores virtuales y entradas dns correspondientes para un proyecto. &lt;a href="http://eddyjosafat.blogspot.com/2010/04/creacion-de-servidores-virtuales-i.html" title="ver primera parte del artículo creación de servidores virtuales"&gt;Puedes ver la primera parte aquí&lt;/a&gt;.&lt;/p&gt;&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;&lt;a href="http://eddyjosafat.blogspot.com/2010/04/creacion-de-servidores-virtuales-i.html" title="ver primera parte del artículo creación de servidores virtuales"&gt;En el artículo anterior&lt;/a&gt; hablé de la creación de subdominios en el servidor de desarrollo para dar soporte al trabajo con los proyectos por parte de cada usuario.&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;ul&gt;  &lt;li&gt;Configurar servidor virtual en el Apache&lt;/li&gt;  &lt;li&gt;Crear un script que automatize tanto la creación de la entrada DNS correspondiente (&lt;a href="http://eddyjosafat.blogspot.com/2010/04/creacion-de-servidores-virtuales-i.html" title="ver primera parte del artículo creación de servidores virtuales"&gt;visto en el artículo anterior&lt;/a&gt;) a cada proyecto como la generación del servidor virtual en el Apache.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Paso a Paso&lt;/h4&gt;&lt;h5&gt;VirtualHost&lt;/h5&gt;&lt;p&gt;Una vez creado el dominio a nivel local, el siguiente paso es configurar el Apache del servidor de desarrollo para que cuando reciba una petición a ese (sub)dominio sepa en qué carpeta se encuentra. El mecanismo para ello es el uso de la directiva VirtualHost.&lt;/p&gt;&lt;p&gt;Esta directiva no solo define la asociación entre un dominio o subdominio y una carpeta específica, sino que además permite establecer una configuración particular del servidor web para esa dirección.&lt;/p&gt;&lt;p&gt;Al instalar el Apache en la Ubuntu, éste crea un virtual host por defecto, denominado &lt;em&gt;default&lt;/em&gt;. Yo hago los siguientes cambios para que después me funcionen los vh de cada proyecto. Estas modificaciones son fundadas en ensayos de prueba y error más que en el conocimiento de como funciona todo esto en el servidor web. Más de un sysadmin se tirará manos a la cabeza si lee esto.&lt;/p&gt;&lt;p&gt;Hay que editar el fichero &lt;em&gt;/etc/apache2/sites-available&lt;/em&gt; y poner en la primera línea:&lt;/p&gt;&lt;code&gt;NameVirtualHost *&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Luego, en la línea siguiente, donde pone:&lt;/p&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&lt;/code&gt;&lt;br /&gt;&lt;p&gt;quito el 80. Así mismo quito la directiva NameVirtualHost * del fichero /etc/apache2/ports.conf, para eliminar redundancias.&lt;/p&gt;&lt;p&gt;Por otro lado, cuando se habilita un servidor virtual con la orden &lt;em&gt;sudo a2ensite&lt;/em&gt;, lo que hace este comando realmente es crear un enlace simbólico en la carpeta &lt;em&gt;/etc/apache2/sites-enabled&lt;/em&gt; apuntando al fichero donde hemos hecho la definición (en &lt;em&gt;/etc/apache2/sites-available&lt;/em&gt;). En estos momentos existirá uno para el default, lo renombro para que se quede como &lt;em&gt;000-default&lt;/em&gt;, ya que asignar 3 dígitos iniciales al nombre del servidor virtual es la convención por defecto que uso.&lt;/p&gt;&lt;h5&gt;Crear para un proyecto&lt;/h5&gt;&lt;p&gt;Básicamente lo que hayo yo es copiar el fichero del servidor 000-default, renombrarlo como 001-nombredeproyecto. Dentro de éste creo una sección VirtualHost para cada usuario del sistema, donde se repite todo menos el nombre del subdominio (todos de la forma nombre_de_usuario.nombre_de_proyecto.it7) y la ruta hacia los ficheros de error del apache, que para cada servidor virtual los sitúo en la carpeta de cada usuario para que acceda a ellos fácilmente para diagnosticar errores.&lt;/p&gt;&lt;p&gt;Así, para un usuario determinado y un proyecto determinado, la directiva VirtualHost quedaría de la siguiente manera: (repitiendolo para cada usuario, todo en el mismo fichero):&lt;/p&gt;&lt;code&gt;&lt;br /&gt; &amp;lt;VirtualHost *&gt;&lt;br /&gt;   ServerName ejosafat.imaco.it7&lt;br /&gt;   DocumentRoot /home/ejosafat/ejosafat.imaco.it7&lt;br /&gt;   &amp;lt;Directory /home/ejosafat/ejosafat.imaco.it7&gt;&lt;br /&gt;     Options FollowSymLinks&lt;br /&gt;     AllowOverride All&lt;br /&gt;     Options -MultiViews&lt;br /&gt;   &amp;lt;/Directory&gt;&lt;br /&gt;&lt;br /&gt;   ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/&lt;br /&gt;   &amp;lt;Directory "/usr/lib/cgi-bin"&gt;&lt;br /&gt;     AllowOverride None&lt;br /&gt;     Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch&lt;br /&gt;     Order allow,deny&lt;br /&gt;     Allow from all&lt;br /&gt;   &amp;lt;/Directory&gt;&lt;br /&gt;&lt;br /&gt;   ErrorLog /home/ejosafat/apache2.imaco.error.log&lt;br /&gt;&lt;br /&gt;   # Possible values include: debug, info, notice, warn, error, crit,&lt;br /&gt;   # alert, emerg.&lt;br /&gt;   LogLevel warn&lt;br /&gt;&lt;br /&gt;   CustomLog /var/log/apache2/access.log combined&lt;br /&gt;   ServerSignature On&lt;br /&gt; &amp;lt;/VirtualHost&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h5&gt;Diferencias entre rails y php en el vh&lt;/h5&gt;&lt;p&gt;La configuración anterior sirve para el típico proyecto en php; tras haber convencido a mi empresa de las bondades del rails respecto al php, todos los proyectos nuevos que encajen en dicho paradigma de programación los desarrollamos en esa tecnología.&lt;/p&gt;&lt;p&gt;Para dichos proyectos, el &lt;em&gt;DocumentRoot&lt;/em&gt;, que es la ruta hacia la carpeta donde se encuentra el proyecto, apuntaría a:&lt;/p&gt;&lt;code&gt;&lt;br /&gt; DocumentRoot /home/ejosafat/ejosafat.imaco.it7/public&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;y si además nos diera por desplegar la aplicación utilizando el &lt;a href="http://www.capify.org/" title="Pulse para ver información sobre esta herramienta"&gt;Capistrano&lt;/a&gt;, entonces habría que apuntar al servidor virtual a:&lt;/p&gt;&lt;code&gt;&lt;br /&gt; DocumentRoot /home/ejosafat/ejosafat.imaco.it7/current/public&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Automatización&lt;/h4&gt;&lt;p&gt;Aquí he sido un poco chapuza, hay aspectos de Ruby que aún estoy aprendiendo, y lo de los paths y demás no lo controlo adecuadamente. El script lo he llamado &lt;em&gt;crear_servidor_virtual.rb&lt;/em&gt;. Puedes hacer un checkout del proyecto y pillar todo el código en el &lt;a href="http://rubyforge.org/projects/autom-proyectos/" title="Accede a la página del proyecto"&gt;RubyForge&lt;/a&gt;. En unos meses espero ya tener una versión mucho más pulida, adaptable, empaquetada como gema y haciendo uso del &lt;a href="http://github.com/carlhuda/bundler"&gt;Bundler&lt;/a&gt; y estará alojada en GitHub.&lt;/p&gt;&lt;p&gt;Lo que he hecho es usar ERB para crear plantillas de la configuración DNS y del VirtualHost, para renderizarlas en la ejecución del script e incluirlas en los ficheros correspondientes de la carpeta etc.&lt;/p&gt;&lt;p&gt;Para recordar que modificaciones había que hacer en la &lt;a href="http://eddyjosafat.blogspot.com/2010/04/creacion-de-servidores-virtuales-i.html" title="Ver como configurar el servidor DNS"&gt;configuración del servidor DNS puedes ver mi artículo anterior&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Las plantillas las situo (manualmente) en la carpeta del servidor que denomino &lt;em&gt;/etc/scripts&lt;/em&gt;, donde se encuentran los ficheros de configuración o datos que usan mis scripts.&lt;/p&gt;&lt;h5&gt;dns_zone.erb&lt;/h5&gt;&lt;code&gt;&lt;br /&gt; zone "&amp;lt;%= project_id %&gt;.it7" {&lt;br /&gt;   type master;&lt;br /&gt;   file "/etc/bind/db.&amp;lt;%= project_id %&gt;.it7";&lt;br /&gt; };&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Ésta es para la inclusión de la nueva zona en el fichero named.conf.local.&lt;/p&gt;&lt;h5&gt;db_local.erb&lt;/h5&gt;&lt;code&gt;&lt;br /&gt; ;&lt;br /&gt; ; BIND data file for local loopback interface&lt;br /&gt; ;&lt;br /&gt; $TTL 604800&lt;br /&gt; @ IN SOA ns.&amp;lt;%= project_id %&gt;.it7. ejosafat.it7.info. (&lt;br /&gt;          2  ; Serial&lt;br /&gt;     604800  ; Refresh&lt;br /&gt;      86400  ; Retry&lt;br /&gt;    2419200  ; Expire&lt;br /&gt;     604800 ) ; Negative Cache TTL&lt;br /&gt; ;&lt;br /&gt; @ IN NS ns.&amp;lt;%= project_id %&gt;.it7&lt;br /&gt; @ IN A 192.168.50.53&lt;br /&gt; &amp;lt;% users.each do |u| %&gt;&lt;br /&gt; &amp;lt;%= u %&gt;    IN A 192.168.50.53&lt;br /&gt; &amp;lt;% end %&gt;&lt;br /&gt; ns IN A 192.168.50.53&lt;br /&gt; @ IN AAAA ::1&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Esta es para la generación del fichero db.nombredeproyecto.it7. Para cada usuario en el sistema se genera una entrada A para su subdominio correspondiente. No hace falta declarar la resolución inversa de la IP, eso solo hace falta hacerlo para el dominio principal, goldberg.it7 (&lt;a href="http://eddyjosafat.blogspot.com/2010/04/creacion-de-servidores-virtuales-i.html"&gt;ver artículo anterior&lt;/a&gt;)&lt;/p&gt;&lt;h5&gt;virtual_host.erb&lt;/h5&gt;&lt;p&gt;Y esta es la plantilla para crear el servidor virtual del apache, una entrada para cada usuario. Si el proyecto es rails, en el &lt;em&gt;DocumentRoot&lt;/em&gt; añado la carpeta &lt;em&gt;public&lt;/em&gt; a la ruta.&lt;/p&gt;&lt;code&gt;&lt;br /&gt; &amp;lt;VirtualHost *&gt;&lt;br /&gt;   ServerName &amp;lt;%= user %&gt;.&amp;lt;%= project_id %&gt;.it7&lt;br /&gt;   DocumentRoot /home/&amp;lt;%= user %&gt;/&amp;lt;%= user %&gt;.&amp;lt;%= project_id %&gt;.it7&amp;lt;%= '/public' if type == 'rails' %&gt;&lt;br /&gt;   &amp;lt;Directory /home/&amp;lt;%= user %&gt;/&amp;lt;%= user %&gt;.&amp;lt;%= project_id %&gt;.it7&gt;&lt;br /&gt;     Options FollowSymLinks&lt;br /&gt;     AllowOverride All&lt;br /&gt;     Options -MultiViews&lt;br /&gt;   &amp;lt;/Directory&gt;&lt;br /&gt;&lt;br /&gt;   ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/&lt;br /&gt;   &amp;lt;Directory "/usr/lib/cgi-bin"&gt;&lt;br /&gt;     AllowOverride None&lt;br /&gt;     Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch&lt;br /&gt;     Order allow,deny&lt;br /&gt;     Allow from all&lt;br /&gt;   &amp;lt;/Directory&gt;&lt;br /&gt;&lt;br /&gt;   ErrorLog /home/&amp;lt;%= user %&gt;/apache2.&amp;lt;%= project_id %&gt;.error.log&lt;br /&gt;&lt;br /&gt;   # Possible values include: debug, info, notice, warn, error, crit,&lt;br /&gt;   # alert, emerg.&lt;br /&gt;   LogLevel warn&lt;br /&gt;&lt;br /&gt;   CustomLog /var/log/apache2/access.log combined&lt;br /&gt;   ServerSignature On&lt;br /&gt; &amp;lt;/VirtualHost&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h5&gt;crear_servidor_virtual.rb&lt;/h5&gt;&lt;p&gt;Como siempre, el script en sí no tiene mucha ciencia:&lt;/p&gt;&lt;code&gt;&lt;br /&gt; check_usage(1, "Usage: crear_servidor_virtual.rb &amp;lt;id de proyecto&gt; [type]")&lt;br /&gt;  id_proyecto = ARGV[0]&lt;br /&gt;  # El tipo por defecto será rails.&lt;br /&gt;  type = ARGV[1] || 'rails'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El script se invoca con un ide proyecto y opcionalmente un tipo. Si no se especifica nada, se asume que es un proyecto rails. La otra opción permitida será php, aunque esto realmente no lo compruebo. Si el usuario no escribe nada como segundo argumento, el servidor virtual apuntará a la subcarpeta public del proyecto, y si pone cualquier cosa apuntará a la carpeta raíz del proyecto.&lt;/p&gt;&lt;code&gt;&lt;br /&gt; users = IO.readlines(USERS_LIST_PATH).each(&amp;amp;:chomp!)&lt;br /&gt; if IO.read(NAMED_CONF_PATH) !~ /#{id_proyecto}/&lt;br /&gt;    open(NAMED_CONF_PATH, 'a') {|f| f &amp;lt;&amp;lt; Project.get_dns_zone(id_proyecto) &amp;lt;&amp;lt; "\n"}&lt;br /&gt;  end&lt;br /&gt; Project.create_db_local(id_proyecto, users)&lt;br /&gt; `sudo /etc/init.d/bind9 restart`&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Tras leer la lista de usuarios, añadiré la entrada de zona al named_conf. Creo el fichero db oportuno para el dns y reinicio el servidor. El método &lt;em&gt;create_db_local&lt;/em&gt; tiene esta forma:&lt;/p&gt;&lt;code&gt;&lt;br /&gt; def self.create_db_local(project_id, users)&lt;br /&gt;    # Cargar plantilla&lt;br /&gt;    template = ERB.new(IO.read(DB_LOCAL_TEMPLATE_PATH))&lt;br /&gt;    # Renderizar plantilla y grabarla en disco&lt;br /&gt;    db_local = "#{DB_LOCAL_PATH}db.#{project_id}.it7"&lt;br /&gt;    open(db_local, "w") {|f| f &lt;&lt; template.result(binding)} if !File.exists? db_local  end&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Simplemente renderiza la plantilla y escribe el fichero en disco a no ser que ya exista de antes.&lt;/p&gt;&lt;code&gt;&lt;br /&gt; vh = ''&lt;br /&gt;  users.each do |u|&lt;br /&gt;    vh += Project.get_vhost({:project_id =&gt; id_proyecto, :user =&gt; u, :type =&gt; type.downcase})&lt;br /&gt;  end&lt;br /&gt;  # localizar último número&lt;br /&gt;  sites = Dir.entries('/etc/apache2/sites-available').reject {|f| f =~ /^\.{1,2}$/ || f =~ /default/}&lt;br /&gt;  # los 3 primeros caracteres del nombre del servidor virtual son el número de secuencia, leemos y asignamos el siguiente.&lt;br /&gt;  last_number = sites.sort.last[0,3].succ&lt;br /&gt;  # crear fichero&lt;br /&gt;  new_vh = "/etc/apache2/sites-available/#{last_number}-#{id_proyecto}"&lt;br /&gt;  open(new_vh, 'w') {|f| f &amp;lt;&amp;lt; vh} unless File.exists? new_vh&lt;br /&gt;  # enlazar en enabled&lt;br /&gt;  `sudo a2ensite #{last_number}-#{id_proyecto}`&lt;br /&gt;  # recargar apache&lt;br /&gt;  `sudo /etc/init.d/apache2 reload`&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Aquí creo el fichero con los servidores virtuales de apache correspondientes a cada usuario. Quizás lo que es más truculento es nombrar el fichero. En mi empresa (y en muchas otras) seguimos la convención de usar numeración consecutiva para los ficheros de servidores virtuales, por lo que primero tengo que detectar el número del último fichero generado para incrementarlo en uno para asignarselo al nuevo. El renderizado del VirtualHost específico para un usuario se hace en la llamada del método &lt;em&gt;get_vhost&lt;/em&gt;:&lt;/p&gt;&lt;code&gt;&lt;br /&gt; def self.get_vhost(options)&lt;br /&gt;    # Cargar plantilla&lt;br /&gt;    template = ERB.new(IO.read(VH_TEMPLATE_PATH))&lt;br /&gt;    user = options[:user]&lt;br /&gt;    type = options[:type]&lt;br /&gt;    project_id = options[:project_id]&lt;br /&gt;    template.result(binding)&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;&lt;p&gt; Con esto automatiza una de las partes más engorrosas y que menos me gustaba a la hora de generar la infraestructura necesaria para el desarrollo del proyecto, y por aquí todos son más felices cuando les digo que generen los servidores virtuales.&lt;br /&gt; En próximos artículos hablaré de otros pequeños scripts accesorios que también me han facilitado esas tareas rutinarias y aburridas, haciéndome un programador más contento :-)&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-4774863419750661355?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/4774863419750661355/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/05/creacion-de-servidores-virtuales-ii.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4774863419750661355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4774863419750661355'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/05/creacion-de-servidores-virtuales-ii.html' title='Creación de servidores virtuales (II)'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-3654340739575871892</id><published>2010-04-08T14:40:00.001+01:00</published><updated>2010-04-08T14:43:44.491+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dns apache virtual_host ruby'/><title type='text'>Creación de servidores virtuales (I)</title><content type='html'>&lt;p&gt;¿Cansado de crear a mano los servidores virtuales del Apache para cada proyecto con sus correspondientes entradas DNS en el servidor de desarrollo local? Yo lo estaba, así que decidí resolverlo con este script.&lt;/p&gt;&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;El modus operandi en mi empresa a la hora de trabajar un proyecto es el siguiente: en el servidor de desarrollo, en la carpeta home de cada usuario, se crea una carpeta para cada proyecto, de la forma nombreDeUsuario.nombreDeProyecto.it7, por ejemplo ejosafat.ciu2010.it7; esa es la copia de trabajo subversion de cada uno.&lt;/p&gt;&lt;p&gt;Cada usuario visualiza su trabajo con el navegador accediendo a la url http://nombreDeUsuario.nombreDeProyecto.it7 correspondiente. Para que esto sea posible, se deben dar dos condiciones:&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Que haya un servidor DNS que reconozca la url y encamine el navegador hacia el servidor de desarrollo.&lt;/li&gt;  &lt;li&gt;Que haya creado un servidor virtual en el Apache que responda a esa dirección sirviendo los archivos de la carpeta correspondiente.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Primero veremos como sería la forma manual de hacerlo (incluyendo la configuración del servidor DNS en el servidor de desarrollo local) y después el script para automatizar dicha generación.&lt;/p&gt;&lt;p&gt;Dada la extensión de este artículo, lo dividiré en dos partes. En ésta hablaré de la configuración DNS, y en el siguiente la configuración de los virtual host en el apache y el script que automatiza la generación.&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;ul&gt;  &lt;li&gt;Configurar servidor DNS&lt;/li&gt;  &lt;li&gt;Crear un script que automatice tanto la creación de la entrada DNS correspondiente a cada proyecto como la generación del servidor virtual en el Apache.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Paso a Paso&lt;/h4&gt;&lt;h5&gt;DNS&lt;/h5&gt;&lt;p&gt;Para configurar el servidor DNS, hay un buen &lt;a href="https://help.ubuntu.com/9.10/serverguide/C/dns-configuration.html" title="Pulse para ver el artículo de la guía del servidor de la Ubuntu 9.10 sobre configuración de un servidor DNS"&gt;artículo al respecto en la guía del servidor de la Ubuntu 9.10&lt;/a&gt;. Resumiré aquí lo que me interesa para la configuración de mi servidor de desarrollo.&lt;/p&gt;&lt;p&gt;Lo primero de todo es configurar cuales serán los servidores DNS que consultará el propio servidor. Hay que editar el fichero &lt;em&gt;/etc/resolv.conf&lt;/em&gt;, y sustituir lo que haya por la dirección IP del propio servidor, ya que será el que tenga que resolver las direcciones de los proyectos que trabajamos en el entorno local. A continuación, en caso de que el servicio DNS falle, ponemos la de otros servidores conocidos (en mi caso uso los de Telefónica generalmente).&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  nameserver 192.168.50.53&lt;br /&gt;  nameserver 194.179.1.100&lt;br /&gt;  nameserver 194.179.1.101&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El primer paso es configurar el servidor de desarrollo como forwarder de DNS. Es decir, que cuando le llegue una petición de resolución de nombres, si él no puede resolverla (cosa que pasará con cualquier dominio que no sea de los que usaremos para el desarrollo local), haga la petición a otro servidor DNS y &lt;strong&gt;cachee la respuesta&lt;/strong&gt;, de tal manera que en sucesivas peticiones al mismo dominio externo obtengamos la respuesta de nuestro propio servidor, que ya conocerá la ip a la que resuelve el nombre, por haberla buscado anteriormente.&lt;/p&gt;&lt;p&gt;Lo primero es configurar para que reconozca el dominio personalizado que usaremos para conectar con el servidor de desarrollo en general, al margen de cualquier proyecto, bien sea por ssh o via web para utilizar el phpmyadmin, por ejemplo.&lt;/p&gt;&lt;p&gt;Hay que editar el fichero &lt;em&gt;/etc/bind/named.conf.local&lt;/em&gt; y añadir lo siguiente (el nombre local de la máquina es goldberg, y el sufijo que usaremos para todos los dominios es it7):&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  zone "goldberg" {&lt;br /&gt;    type master;&lt;br /&gt;    file "/etc/bind/db.goldberg.it7";&lt;br /&gt;  };&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;y su resolución inversa correspondiente:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  zone "50.168.192.in-addr.arpa" {&lt;br /&gt;    type master;&lt;br /&gt;    notify no;&lt;br /&gt;    file "/etc/bind/db.192";&lt;br /&gt;  };&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Hay que crear los dos ficheros referenciados, ambos en la carpeta &lt;em&gt;/etc/bind&lt;/em&gt;. Para crear el fichero &lt;em&gt;db.192&lt;/em&gt;, lo más cómodo es copiar uno que se habrá creado en la instalación del servidor, db.127, y modificarlo para dejarlo así:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  $TTL    604800&lt;br /&gt;  @       IN      SOA     .goldberg.it7. ejosafat.it7.info. (&lt;br /&gt;  1         ; Serial&lt;br /&gt;  604800         ; Refresh&lt;br /&gt;  86400         ; Retry&lt;br /&gt;  2419200         ; Expire&lt;br /&gt;  604800 )       ; Negative Cache TTL&lt;br /&gt;  ;&lt;br /&gt;  @       IN      NS      .&lt;br /&gt;  53      IN      PTR     .goldberg.it7.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Para crear &lt;em&gt;db.goldberg.it7&lt;/em&gt;, lo más sencillo también es copiar otro que ya existirá, &lt;em&gt;db.local&lt;/em&gt; y modificarlo, para dejarlo de la siguiente manera:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  ;&lt;br /&gt;  ; BIND data file for local loopback interface&lt;br /&gt;  ;&lt;br /&gt;  $TTL 604800&lt;br /&gt;  @ IN SOA ns.goldberg.it7. ejosafat.it7.info. (&lt;br /&gt;           2  ; Serial&lt;br /&gt;      604800  ; Refresh&lt;br /&gt;       86400  ; Retry&lt;br /&gt;     2419200  ; Expire&lt;br /&gt;      604800 ) ; Negative Cache TTL&lt;br /&gt;  ;&lt;br /&gt;  @ IN NS ns.goldberg.it7&lt;br /&gt;  @ IN A 192.168.50.53&lt;br /&gt;  @ IN AAAA ::1&lt;br /&gt;  ns IN A 192.168.50.53 &lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;posteriormente, para cada proyecto que se vaya a emprender, hay que crear también la correspondiente entrada en &lt;em&gt;/etc/bind/named.conf.local&lt;/em&gt;, de la misma manera. Por ejemplo, para un proyecto denominado &lt;em&gt;prueba&lt;/em&gt;:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  zone "prueba.it7" {&lt;br /&gt;    type master;&lt;br /&gt;    file "/etc/bind/db.prueba.it7";&lt;br /&gt;  };&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Y hay que crear &lt;em&gt;db.prueba.it7&lt;/em&gt;, para ello se puede copiar el fichero db.golberg.it7 y realizar los siguientes cambios:&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;sustituir &lt;em&gt;goldberg&lt;/em&gt; por &lt;em&gt;prueba&lt;/em&gt;&lt;/li&gt;  &lt;li&gt;Añadir debajo de la línea &lt;em&gt;@ IN A 192.168.50.53&lt;/em&gt; una línea para cada subdominio (desarrollador que va a trabajar en el proyecto) de la forma &lt;em&gt;&amp;lt;nombre de usuario&gt; IN A 192.168.50.53&lt;/em&gt;. Por ejemplo, para eddy, usaríamos &lt;em&gt;eddy IN A 192.168.50.53&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;&lt;p&gt;De esta manera se pueden ir creando todos los dominios que necesite para el desarrollo de los diversos proyectos. Más de un administrador de sistemas se tirará manos a la cabeza leyendo lo anterior, ya que no hablo del incremento del número Serial, y probablemente haya otra forma más elegante de hacerlo, pero soy programador, no sysadmin, a mí así me vale!&lt;/p&gt;&lt;p&gt;En el próximo artículo configuraré el Apache para responder a esas direcciones y utilizaré un script para automatizar tan tediosa tarea.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-3654340739575871892?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/3654340739575871892/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/04/creacion-de-servidores-virtuales-i.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3654340739575871892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3654340739575871892'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/04/creacion-de-servidores-virtuales-i.html' title='Creación de servidores virtuales (I)'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-1369191135857763309</id><published>2010-03-19T15:23:00.000Z</published><updated>2010-03-19T15:23:09.949Z</updated><title type='text'>Backup via FTP automatizado con Ruby</title><content type='html'>&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;Ya están las carpetas de trabajo de los usuarios de la empresa en el servidor de desarrollo (Goldberg), el repositorio subversion local sincronizado con el de Dreamhost, y además se hace una exportación de todos los proyectos todas las noches. El siguiente paso es hacer una copia de seguridad de todo esto, junto con la configuración de Goldberg.&lt;/p&gt;&lt;p&gt;En la empresa donde trabajo actualmente, tienen un servidor Windows 2003 Server con una unidad de cinta que copia los contenidos de su disco duro y de algunos más en distintos ordenadores de la red interna (todos Windows, of course, a los usuarios de Mac y Linux que nos den!). Lo que voy a hacer es crear un script que coja el contenido de varias carpetas seleccionadas y las mande por FTP a una de las máquinas cuya información entra en la copia de seguridad.&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;p&gt;Quiero que todas las noches se copien las carpetas importantes del servidor de desarrollo en otra máquina, via FTP.&lt;/p&gt;&lt;h4&gt;Paso a Paso&lt;/h4&gt;&lt;p&gt;La lista de carpetas a exportar las pongo en un fichero de texto ubicado en la carpeta &lt;em&gt;/etc/scripts&lt;/em&gt; del servidor de desarrollo, con el nombre &lt;em&gt;backup_folders&lt;/em&gt;. Las carpetas importantes en mi caso son:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  /etc (ficheros de configuración del servidor)&lt;br /&gt;  /home/eddy  (carpetas de trabajo de los usuarios)&lt;br /&gt;      .....&lt;br /&gt;  /var/exported_projects (copia en limpio de los proyectos)&lt;br /&gt;  /var/subversion (carpeta donde se encuentran los repositorios)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Por otro lado, tenemos en la oficina una máquina Windows con un servidor FTP instalado, sin cuentas, permitiendo la subida anónima de ficheros. La carpeta donde se almacenan las subidas entra en la copia en seguridad en cinta que realiza el servidor Windows 2003 Server de la empresa.&lt;/p&gt;&lt;h4&gt;Automatización&lt;/h4&gt;&lt;p&gt;El script &lt;em&gt;backup.rb&lt;/em&gt; se encarga de realizar la tarea de comprimir las carpetas especificadas en el fichero &lt;em&gt;/etc/scripts/backup_folders&lt;/em&gt;, especificado en la constante &lt;em&gt;BACKUP_LIST_PATH&lt;/em&gt;, y enviarlas por ftp a una máquina especificada. Puedes &lt;a href="http://rubyforge.org/projects/autom-proyectos/" title="Ir a la página del proyecto autom-proyectos en RubyForge"&gt;bajarte estos scripts desde rubyforge&lt;/a&gt;.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  folder_list_file = ARGV[0] || BACKUP_LIST_PATH&lt;br /&gt;  tmp_folder = ARGV[1] || '/tmp'&lt;br /&gt;  Net::FTP.open('192.168.50.102') do |ftp|&lt;br /&gt;    ftp.login&lt;br /&gt;    File.open(folder_list_file).readlines.each do |line|&lt;br /&gt;      line.chomp!&lt;br /&gt;      puts "tar #{line}"&lt;br /&gt;      line =~ /([_a-z]*)$/&lt;br /&gt;      filename = $1&lt;br /&gt;      `tar -cz #{line} &gt; #{tmp_folder}/#{filename}.tgz`&lt;br /&gt;      ftp.putbinaryfile "#{tmp_folder}/#{filename}.tgz"&lt;br /&gt;      `rm #{tmp_folder}/#{filename}.tgz`&lt;br /&gt;    end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El script no tiene mucha ciencia: abre una conexión ftp con la máquina en cuestión, y para cada una de las carpetas especificadas realiza la compresión en la carpeta temporal del sistema, envía el fichero tgz creado a la máquina FTP y tras esto lo borra de la carpeta temporal.&lt;/p&gt;&lt;p&gt;Tras meter una entrada en el &lt;em&gt;crontab&lt;/em&gt; para que todas las noches llame al script, ya solo queda revisar los emails que envia el servidor de desarrollo para comprobar que la copia se está realizando correctamente y dormir tranquilo!&lt;/p&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;Voy a convencer a mi empresa para usar el Amazon S3 como backup alternativo, con lo que más adelante cambiaré todo esto. De momento me aseguro de tener lo esencial del servidor de desarrollo a salvo en otra máquina y en cinta, y sigo moviéndome adelante. Lo próximo: scripts para crear servidores virtuales de apache (incluyendo sus correspondientes entradas dns) para cada proyecto que se empiece.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-1369191135857763309?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/1369191135857763309/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/03/backup-via-ftp-automatizado-con-ruby.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/1369191135857763309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/1369191135857763309'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/03/backup-via-ftp-automatizado-con-ruby.html' title='Backup via FTP automatizado con Ruby'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-3561895787662798350</id><published>2010-03-19T10:13:00.000Z</published><updated>2010-03-19T10:13:17.873Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='derechos'/><category scheme='http://www.blogger.com/atom/ns#' term='psoe'/><category scheme='http://www.blogger.com/atom/ns#' term='Ley Sinde'/><title type='text'>En defensa de los derechos fundamentales en Internet</title><content type='html'>&lt;span class="Apple-style-span" style="color: #333333; font-family: Helvetica, sans-serif; font-size: 12px; line-height: 15px;"&gt;&lt;/span&gt;&lt;br /&gt;Ante la inclusión en el Poyectroyecto de Ley de Economía sostenible de modificaciones legislativas que afectan al libre ejercicio de las libertades de expresión, información y el derecho de acceso a la cultura a través de Internet, los periodistas,&amp;nbsp;&lt;em&gt;bloggers&lt;/em&gt;, usuarios, profesionales y creadores de Internet manifestamos nuestra firme oposición al proyecto, y declaramos que:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span&gt;Los derechos de autor no pueden situarse por encima de los derechos fundamentales de los ciudadanos&lt;/span&gt;, como el derecho a la privacidad, a la seguridad, a la presunción de inocencia, a la tutela judicial efectiva y a la libertad de expresión.&lt;/li&gt;&lt;li&gt;&lt;span&gt;La suspensión de derechos fundamentales es y debe seguir siendo competencia exclusiva del poder judicia&lt;/span&gt;l. Ni un cierre sin sentencia. Este anteproyecto, en contra de lo establecido en el artículo 20.5 de la Constitución, pone en manos de un órgano no judicial -un organismo dependiente del ministerio de Cultura-, la potestad de impedir a los ciudadanos españoles el acceso a cualquier página web.&lt;/li&gt;&lt;li&gt;&lt;span&gt;La nueva legislación creará inseguridad jurídica en todo el sector tecnológico español&lt;/span&gt;, perjudicando uno de los pocos campos de desarrollo y futuro de nuestra economía, entorpeciendo la creación de empresas, introduciendo trabas a la libre competencia y ralentizando su proyección internacional.&lt;/li&gt;&lt;li&gt;&lt;span&gt;La nueva legislación propuesta amenaza a los nuevos creadores y entorpece la creación cultural.&lt;/span&gt;&amp;nbsp;Con Internet y los sucesivos avances tecnológicos se ha democratizado extraordinariamente la creación y emisión de contenidos de todo tipo, que ya no provienen prevalentemente de las industrias culturales tradicionales, sino de multitud de fuentes diferentes.&lt;/li&gt;&lt;li&gt;&lt;span&gt;Los autores&lt;/span&gt;, como todos los trabajadores,&amp;nbsp;&lt;span&gt;tienen derecho a vivir de su trabajo con nuevas ideas creativas, modelos de negocio y actividades&lt;/span&gt;&amp;nbsp;asociadas a sus creaciones. Intentar sostener con cambios legislativos a una industria obsoleta que no sabe adaptarse a este nuevo entorno no es ni justo ni realista. Si su modelo de negocio se basaba en el control de las copias de las obras y en Internet no es posible sin vulnerar derechos fundamentales, deberían buscar otro modelo.&lt;/li&gt;&lt;li&gt;Consideramos que&amp;nbsp;&lt;span&gt;las industrias culturales necesitan para sobrevivir alternativas modernas, eficaces, creíbles y asequibles y que se adecuen a los nuevos usos sociales,&lt;/span&gt;&amp;nbsp;en lugar de limitaciones tan desproporcionadas como ineficaces para el fin que dicen perseguir.&lt;/li&gt;&lt;li&gt;&lt;span&gt;Internet debe funcionar de forma libre y sin interferencias políticas&lt;/span&gt;&amp;nbsp;auspiciadas por sectores que pretenden perpetuar obsoletos modelos de negocio e imposibilitar que el saber humano siga siendo libre.&lt;/li&gt;&lt;li&gt;&lt;span&gt;Exigimos que el Gobierno garantice por ley la neutralidad de la Red en España,&lt;/span&gt;&amp;nbsp;ante cualquier presión que pueda producirse, como marco para el desarrollo de una economía sostenible y realista de cara al futuro.&lt;/li&gt;&lt;li&gt;&lt;span&gt;Proponemos una verdadera reforma del derecho de propiedad intelectual&lt;/span&gt;&amp;nbsp;orientada a su fin: devolver a la sociedad el conocimiento, promover el dominio público y limitar los abusos de las entidades gestoras.&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;En democracia las leyes y sus modificaciones deben aprobarse tras el oportuno debate público&lt;/span&gt;&amp;nbsp;y habiendo consultado previamente a todas las partes implicadas. No es de recibo que se realicen cambios legislativos que afectan a derechos fundamentales en una ley no orgánica y que versa sobre otra materia.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;div&gt;&lt;/div&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-3561895787662798350?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/3561895787662798350/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/03/en-defensa-de-los-derechos.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3561895787662798350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/3561895787662798350'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/03/en-defensa-de-los-derechos.html' title='En defensa de los derechos fundamentales en Internet'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-2274858153525939908</id><published>2010-02-27T00:18:00.000Z</published><updated>2010-02-27T00:18:55.415Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='subversion ruby script'/><title type='text'>Exportación de repositorios con Ruby</title><content type='html'>&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;&lt;a href="http://eddyjosafat.blogspot.com/2010/02/automatizando-el-volcado-de.html" title="Pulsa para ver los scripts de automatización de la sincronización entre repositorios subversion"&gt;En el artículo anterior&lt;/a&gt;, crée la infraestructura básica para los scripts de automatización de las tareas relacionadas con proyectos. Una vez solucionado el tema de sincronizar los repositorios subversion de Dreamhost y local, le toca el turno al script para exportar los proyectos y tener una copia en limpio que entre en la copia de seguridad de la empresa.&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;p&gt;Tener un script que realice la exportación automática de todos los proyectos que se encuentran en el repositorio subversion, para tener una copia en limpio de ellos para entrar en la copia de seguridad diaria de la empresa.&lt;/p&gt;&lt;h4&gt;Paso a paso&lt;/h4&gt;&lt;p&gt;Previamente preparo una carpeta para alojar los proyectos exportados:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  sudo mkdir /var/exported_projects&lt;br /&gt;  sudo chgrp www-data /var/exported_projects&lt;br /&gt;  sudo chmod g+w /var/exported_projects&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Para exportar un proyecto el comando a usar es:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  svn export http://urlrepositorio.com/proyecto/trunk /var/exported_projects/proyecto&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Lo cual exportaría el proyecto en la carpeta del mismo nombre. Una vez más, hacer esto manualmente todos los días para todos los proyectos sería desquiciante.&lt;/p&gt;&lt;h4&gt;Automatización&lt;/h4&gt;&lt;p&gt;Basándonos en el código visto en el &lt;a href="http://eddyjosafat.blogspot.com/2010/02/automatizando-el-volcado-de.html"&gt;artículo sobre la automatización de la sincronización de repositorios subversion&lt;/a&gt;, basta añadir un método a la clase Repository para hacer la exportación. Puedes &lt;a href="http://rubyforge.org/projects/autom-proyectos/"&gt;descargarte el código en el RubyForge&lt;/a&gt;.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  def export(options = {})&lt;br /&gt;    `cd #{options[:folder]}; rm -rf #{options[:project_id]}; svn export --username #{options[:username]} --password #{options[:password]} #{@url}/#{options[:project_id]}/trunk #{options[:project_id]}` =~ /exported/i&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Este método acepta como parámetros la carpeta donde se almacenan los proyectos exportados (:folder), el id del proyecto (:project_id), el nombre de usuario para conectarse al servidor subversion y su contraseña (:username, :password), devolviendo verdadero o falso.&lt;/p&gt;&lt;p&gt;A continuación el script para realizar la exportación, mismo mecanismo que los anteriores scripts. Apoyándose en un fichero de texto que incluye un listado de proyectos activos, el script &lt;em&gt;exportar_repositorios.rb&lt;/em&gt; sencillamente va proyecto a proyecto exportandolos en la carpeta especificada.&lt;/p&gt;&lt;p&gt;El script acepta como argumentos obligatorios el usuario y la contraseña con la que conectarse al repositorio, y como opcionales la ruta hacia el listado de proyectos y la carpeta donde exportarlos. No hay nada extraño en el script, salvo la línea:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  ENV['LC_CTYPE'] = 'en_US.UTF-8'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;que tuve incluir porque tenía problemas con las diferencias de codificación entre el servidor de Dreamhost y el mio. Aquí el código del script:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  if $0 == __FILE__&lt;br /&gt;    with_pleasant_exceptions do&lt;br /&gt;      check_usage(2, 'Uso: exportar_repositorios.rb &lt;user&gt; &lt;password&gt; [ruta hacia el listado de proyectos] [carpeta de exportación]')&lt;br /&gt;      proyectos = Project.new(:list_path =&gt; ARGV[2], :export_path =&gt; ARGV[3])&lt;br /&gt;      user = ARGV[0]&lt;br /&gt;      password = ARGV[1]&lt;br /&gt;      # actualizar repositorio para cada proyecto de la lista&lt;br /&gt;      failed_exports = []&lt;br /&gt;      ok_exports = []&lt;br /&gt;      repository = Repository.new&lt;br /&gt;      # Solucionar problemas en la exportación por incompatibilidad de caracteres&lt;br /&gt;      ENV['LC_CTYPE'] = 'en_US.UTF-8'&lt;br /&gt;&lt;br /&gt;      proyectos.list.each do |proyecto|&lt;br /&gt;        # Problemas en el repositorio de Dreamhost hace que el project_id para la linea de comandos y el usado en el&lt;br /&gt;        # nombre del repositorio difieran&lt;br /&gt;        proyecto[:project_id] = 'seguridad' if proyecto[:project_id] == 'canariassegura'&lt;br /&gt;        if repository.export(:folder =&gt; proyectos.export_path, :project_id =&gt; proyecto[:project_id], :user =&gt; user, :password =&gt; password)&lt;br /&gt;          ok_exports &amp;lt;&amp;lt; proyecto[:project_id]&lt;br /&gt;        else&lt;br /&gt;          failed_exports &amp;lt;&amp;lt; proyecto[:project_id]&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;      puts "Proyectos exportados:\n"&lt;br /&gt;      puts ok_exports&lt;br /&gt;      puts "Proyectos no exportados:\n"&lt;br /&gt;      puts failed_exports&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Hay una línea en concreto que es para solucionar un problema que tuvimos en Dreamhost con un proyecto en concreto:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  proyecto[:project_id] = 'seguridad' if proyecto[:project_id] == 'canariassegura'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;La incluyo por la coña más que nada, porque casi toda la gente que conozco tiene más de un muerto de estos en su armario! ;-)&lt;/p&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;&lt;p&gt;Una vez metemos en el &lt;em&gt;crontab&lt;/em&gt; la línea para llamar a este script y realizar una exportación todas las noches, lo siguiente es preparar un script que coja estos ficheros y los cuelgue via ftp en una máquina cuyo disco duro si que entra en la copia de seguridad diaria del servidor principal de la empresa. (para más información de contexto, ver el &lt;a href="http://eddyjosafat.blogspot.com/2009/12/arrancando.html"&gt;artículo introductorio de este blog&lt;/a&gt;)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-2274858153525939908?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/2274858153525939908/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/02/exportacion-de-repositorios-con-ruby.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/2274858153525939908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/2274858153525939908'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/02/exportacion-de-repositorios-con-ruby.html' title='Exportación de repositorios con Ruby'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-4463710655452636297</id><published>2010-02-18T11:03:00.000Z</published><updated>2010-02-18T11:03:08.242Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='subversion ruby script'/><title type='text'>Automatizando el volcado de repositorios</title><content type='html'>&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;&lt;a href="http://eddyjosafat.blogspot.com/2010/01/estableciendo-un-repositorio-subversion.html"&gt;En el artículo anterior&lt;/a&gt;, establecí un repositorio en el servidor de desarrollo local, &lt;em&gt;Goldberg&lt;/em&gt;, que se sincroniza con el repositorio principal situado en Dreamhost. Comenté los comandos del subversion necesarios para realizar dicha tarea; tales comandos, ejecutados manualmente y a diario, pueden consumir bastante tiempo, el cual es más rentable si lo invertimos en tareas creativas, complejas y divertidas, por lo que he desarrollado unos sencillos scripts que ejecutarán dichas tareas por mi.&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;ul&gt;  &lt;li&gt;Crear scripts para realizar la sincronización entre ambos repositorios. Serán ejecutados desde el crontab.&lt;/li&gt;  &lt;li&gt;Crear la infraestructura de soporte para dichos scripts y los sucesivos que ire desarrollando en mis tareas de automatización.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Consideraciones&lt;/h4&gt;&lt;p&gt;El lenguaje de implementación de los scripts es Ruby. ¿Por qué? Pues porque hace mucho tiempo que no me divertía programando, ya se me hacía pesadísimo, y este lenguaje devuelve la sonrisa a tu rostro a medida que te familiarizas con el y te enamoras del código que vas creando, mucho más compacto, más legible, más flexible, más.... que en los otros lenguajes que conozco. Actualmente estoy explorando otros, como el Clojure, para abordar otros paradigmas de programación de manera agradable también. Para aquellos que quieran aprender Ruby (lo cual recomiendo) se puede acceder de forma gratuita al libro (disponible online gratuitamente) &lt;a href="http://ruby-doc.org/docs/ProgrammingRuby/"&gt;Programming Ruby&lt;/a&gt;, del cual hay una versión (no gratuita) más reciente que incluye la versión 1.9 de este lenguaje. Los scripts están desarrolados con la 1.8.7. Más información sobre Ruby, en &lt;a href="http://www.ruby-lang.org/es/"&gt;la página del lenguaje&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Inicialmente desarrollé las clases y scripts de manera "dispersa", por decirlo de alguna manera, mientras leía el libro de Brian Marick titulado &lt;a href="http://http://pragprog.com/titles/bmsft/everyday-scripting-with-ruby"&gt;Everyday Scripting with Ruby: for Teams, Testers, and You&lt;/a&gt;. Tras haber mejorado mis habilidades como scripter, decidí empaquetarlo todo en un módulo al que denomino Proyectos, que incluye los scripts que iré presentando en este blog así como las clases en las que se apoya.&lt;/p&gt;&lt;p&gt;He creado un proyecto en el RubyForge denominado &lt;a href="http://rubyforge.org/projects/autom-proyectos/"&gt;autom-proyectos&lt;/a&gt;, donde puedes descargarte el paquete. En la página del proyecto verás como hacer checkout del repositorio y tener siempre la última versión del código que voy desarrollando en este blog.&lt;/p&gt;&lt;h4&gt;s4t-utils&lt;/h4&gt;&lt;p&gt;Para la estructuración del paquete me baso en librería mencionada en el libro de Brian Marick (comentado anteriormente). Esta utilidad no solo te genera automáticamente la estructura, sino que se incorpora a él para proporcionar una serie de facilidades de programación (ajustar paths, facilidades para el testing, etc...). Otra alternativa hubiera sido distribuirlo como gema, pero eso ya lo haré más adelante.&lt;/p&gt;&lt;p&gt;En la carpeta bin se sitúan los scripts que realizan las distintas acciones, y en la carpeta lib, los ficheros que forman el módulo Proyectos, que da soporte a dichas utilidades, con las clases Project y Repository (no estaba muy inspirado el día que elegí los nombres).&lt;/p&gt;&lt;p&gt;Así mismo tenemos la carpeta doc, con la documentación del módulo en formato html y que se puede regenerar en cualquier momento sitúandonos en la carpeta raíz del paquete y ejecutando:&lt;/p&gt;&lt;code&gt;rake rdoc&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Por último, en la carpeta test encontramos los tests del módulo. A continuación voy a explicar los ficheros principales, pero no mostraré todo el código para no hacer esto eterno. Descárgate las fuentes en el &lt;a href="http://rubyforge.org/projects/autom-proyectos/"&gt;RubyForge&lt;/a&gt;. Me limitaré a comentar algunos fragmentos y en bastantes de ellos incluyo los comentarios del código para explicarlo.&lt;/p&gt;&lt;p&gt;Puedes ejecutar los scripts desde la línea de comandos con &lt;em&gt;Ruta hacia la carpeta del módulo/bin/volcar_repositorios.rb&lt;/em&gt; o ejecutar (como sudo) &lt;em&gt;rake install&lt;/em&gt; desde la carpeta raíz del proyecto.&lt;/p&gt;&lt;h4&gt;Módulo Proyectos (lib/proyectos.rb)&lt;/h4&gt;&lt;p&gt;Aquí defino los valores predeterminados de configuración. Para personalizar no hay más que cambiar el valor de las variables. Así vale, aunque lo ideal a medida que se incluyan más rutas y se vaya generalizando es cambiar estas constantes por un fichero de configuración YAML.&lt;/p&gt;&lt;p&gt;Aquí se define también el método &lt;em&gt;check_usage&lt;/em&gt;:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;def check_usage(num_required_args, message)&lt;br /&gt;  unless ARGV.length &gt;= num_required_args&lt;br /&gt;    puts message&lt;br /&gt;    exit&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Este método es invocado por aquellos scripts que requieran argumentos obligatorios a la hora de ejecutarse. Si el número de argumentos presentes en la línea de comandos del script es inferior al de los que requiere, muestra por pantalla el mensaje especificado y termina la ejecución del script.&lt;/p&gt;&lt;h4&gt;Project (lib/proyectos/project.rb)&lt;/h4&gt;&lt;p&gt;Esta clase gestiona el acceso al listado de proyectos, de momento es muy simple pero con el tiempo evolucionará (y probablemente se renombrará, en realidad debería haberse llamado ProjectList o algo similar en su actual encarnación) para acomodar todo el modelado de la generación automática de proyectos.&lt;/p&gt;&lt;p&gt;Tiene tres atributos, que son las rutas hacia ficheros o carpetas relevantes. En la inicialización, si no se ha definido alguna de estas rutas se cogen los valores por defecto establecidos en la declaración del módulo Proyectos.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;attr_accessor :list_path, :export_path, :dump_path&lt;br /&gt;&lt;br /&gt;# No comprueba la existencia de las carpetas. Se manejarán las excepciones en cada caso.&lt;br /&gt;# Los atributos tomaran el valor especificado por defecto en la definicion del modulo o los indicados en options.&lt;br /&gt;# * :list_path =&gt; Fichero con el listado de proyectos existentes&lt;br /&gt;# * :export_path =&gt; Carpeta para la exportacion de proyectos&lt;br /&gt;# * :dump_path =&gt; Carpeta para el volcado de repositorios&lt;br /&gt;def initialize(options = {})&lt;br /&gt;  @list_path = options[:list_path] || PROJECT_LIST_PATH&lt;br /&gt;  @export_path = options[:export_path] || EXPORTED_PROJECTS_PATH&lt;br /&gt;  @dump_path = options[:dump_path] || SVN_DUMP_PATH&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Y define un único método, que accede al listado de proyectos para devolverlo en forma de array. El fichero de lista de proyectos es un fichero de texto donde en cada línea se encuentra el identificador del proyecto, seguido de : y el número de la última revisión existente en el repositorio local. Cuando se inicia un proyecto nuevo, se añade una entrada a la lista con el identificador seguido de :0. Se puede ver un ejemplo en /test/data/project_list.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;# Devuelve un array de proyectos, cada uno especificado por un hash con las claves&lt;br /&gt;# * :project_id, que es la cadena identificativa del proyecto.&lt;br /&gt;# * :revision, ultima revision almacenada en el repositorio del servidor de desarrollo local.&lt;br /&gt;def list&lt;br /&gt;  lista = []&lt;br /&gt;  File.open(@list_path).readlines.each do |linea|&lt;br /&gt;    proyecto = linea.chomp.split(':')&lt;br /&gt;    lista &amp;lt;&amp;lt; {:project_id =&gt; proyecto[0], :revision =&gt; proyecto[1].to_i}&lt;br /&gt;  end&lt;br /&gt;  lista&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Repository (lib/proyectos/repository.rb)&lt;/h4&gt;&lt;p&gt;Esta clase gestiona el acceso al repositorio subversion. Todas las operaciones las realiza invocando comandos del shell.&lt;/p&gt;&lt;p&gt;Tiene un solo atributo, que indica la url del repositorio. Si no se especifica un valor por defecto en la inicialización, coge el establecido por defectos en la definición del módulo Proyectos.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;attr_accessor :url&lt;br /&gt;&lt;br /&gt;# Crea una instancia vinculada a un repositorio especificado en la construccion&lt;br /&gt;# o el establecido por defecto para el modulo.&lt;br /&gt;# * url = url del repositorio, incluyendo la parte del protocolo.&lt;br /&gt;def initialize(url = nil)&lt;br /&gt;  @url = url || DEFAULT_REPOSITORY&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El método que realiza el volcado de un repositorio especificado por un identificador, en la carpeta especificada entre dos revisiones. Lo único que hacemos es invocar el comando de sistema &lt;em&gt;svnadmin dump&lt;/em&gt;&lt;/p&gt;&lt;code&gt;&lt;br /&gt;# Vuelca un conjunto de revisiones de un proyecto. El fichero se denominara svn. seguido del valor de :project_id&lt;br /&gt;# options debe ser:&lt;br /&gt;# * :project_id =&gt; Identificador del proyecto&lt;br /&gt;# * :rstart =&gt; Revision de comienzo&lt;br /&gt;# * :rend =&gt; Revision final&lt;br /&gt;# * :folder =&gt; Carpeta donde se almacena el volcado&lt;br /&gt;def dump(options = {})&lt;br /&gt;  `svnadmin dump #{@url}/#{options[:project_id]} --incremental --revision #{options[:rstart]}:#{options[:rend]} &gt; #{options[:folder]}/svn.#{options[:project_id]}`&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Este es el método para cargar un volcado en un repositorio, necesita tan solo conocer la carpeta destino y el identificador de proyecto. Tira del comando &lt;em&gt;svnadmin load&lt;/em&gt;&lt;/p&gt;&lt;code&gt;&lt;br /&gt;# Carga un fichero de volcado de transacciones de un repositorio subversion.&lt;br /&gt;# options debe ser:&lt;br /&gt;# * :folder =&gt; carpeta en la que se encuentra el volcado.&lt;br /&gt;# * :project_id =&gt; cadena identificadora valida de un proyecto.&lt;br /&gt;# El nombre del fichero que espera encontrar el metodo es svn. seguido por el valor de :project_id.&lt;br /&gt;def load(options = {})&lt;br /&gt;  `svnadmin load #{@url}/#{options[:project_id]} &amp;lt; #{options[:folder]}/svn.#{options[:project_id]}`&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El siguiente método es el que permite obtener cual es la última versión en un repositorio. Se utiliza para comparar esta versión con la presente en el fichero de lista de proyectos y poder averiguar entre que revisiones debe hacerse el volcado.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;# Devuelve entero indicando ultima revision del repositorio&lt;br /&gt;# * project_id = cadena identificadora valida de un proyecto.&lt;br /&gt;def last_revision(project_id)&lt;br /&gt;  `svnlook youngest #{@url}/#{project_id}`.chomp.to_i&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Los scripts&lt;/h4&gt;&lt;h5&gt;volcar_repositorios.rb (bin/volcar_repositorios.rb)&lt;/h5&gt;&lt;p&gt;Este es el script que realiza el volcado de los repositorios de Dreamhost. Se sube este paquete y se ejecuta, incluyéndolo en el crontab. No voy a explicar como se hace, puedes verlo &lt;a href="http://blogdrake.net/node/2171"&gt;en este tutorial&lt;/a&gt;. Los comentarios explican lo suficientemente bien el código:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;# Obtener lista de proyectos y revisiones&lt;br /&gt;proyectos = Project.new(:list_path =&gt; '/home/cuentait7/etc/project_list', :dump_path =&gt; '~/svndumps')&lt;br /&gt;repositorio = Repository.new('/home/cuentait7/svn')&lt;br /&gt;&lt;br /&gt; # Para cada proyecto realizar el volcado en la carpeta correspondiente&lt;br /&gt; proyectos.list.each do |proyecto|&lt;br /&gt;   # Ver cual es la revisión actual, obteniendo la información del repositorio que se va a volcar&lt;br /&gt;   actual = repositorio.last_revision(proyecto[:project_id])&lt;br /&gt;   # Ver cual es la revisión de Goldberg, información obtenida de la lista de proyectos&lt;br /&gt;   previa = proyecto[:revision]&lt;br /&gt;&lt;br /&gt;   # Hacer el volcado entre la siguiente revisión a la que está en Goldberg y la actual&lt;br /&gt;   if previa != actual&lt;br /&gt;     puts "volcando #{proyecto[:project_id]}"&lt;br /&gt;     repositorio.dump(:project_id =&gt; proyecto[:project_id], :rstart =&gt; previa + 1, :rend =&gt; actual, :folder =&gt; proyectos.dump_path)&lt;br /&gt;   end &lt;br /&gt; end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;h5&gt;cargar_repositorios.rb (bin/cargar_repositorios.rb)&lt;/h5&gt; &lt;p&gt;Primero establecemos la lista, el repositorio, la carpeta donde se realiza el volcado en Dreamhost....&lt;/p&gt;&lt;code&gt;&lt;br /&gt;proyectos = Project.new&lt;br /&gt;repositorio = Repository.new('/var/subversion')&lt;br /&gt;lista = proyectos.list&lt;br /&gt;dh_folder = '/home/cuentait7/svndumps'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;A continuación abro una conexión ssh, usando como identificador &lt;a href="http://eddyjosafat.blogspot.com/2010/01/instalacion-del-servidor-de-desarrollo.html#genera_key_rsa" title="Pulsa para ver como generar una clave rsa y no tener que autentificarte con contraseña en el acceso ssh"&gt;la clave que generé cuando instalé el servidor&lt;/a&gt;.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;Net::SSH.start('greene.dreamhost.com', 'cuentait7', {:keys =&gt; ['/home/eddy/.ssh/id_rsa']}) do |ssh|&lt;br /&gt;  puts "Conexión realizada con éxito"&lt;br /&gt;  lista.each do |proyecto|&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Para cada proyecto que hay en la lista, hay que:&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Establecer las rutas hacia el fichero remoto y hacia el local.&lt;br /&gt;    &lt;code&gt;&lt;br /&gt;      dh_project_url = "#{dh_folder}/svn.#{proyecto[:project_id]}"&lt;br /&gt;      local_project_url = "#{proyectos.dump_path}/svn.#{proyecto[:project_id]}"&lt;br /&gt;    &lt;/code&gt;&lt;br /&gt;  &lt;/li&gt;  &lt;li&gt;Si existe un volcado del proyecto en cuestión lo descargamos.&lt;br /&gt;    &lt;code&gt;&lt;br /&gt;      if ssh.exec!("ls #{dh_project_url}") !~ /No such/&lt;br /&gt;        # obtener el fichero de Dreamhost&lt;br /&gt;        ssh.sftp.download!("#{dh_project_url}", local_project_url)&lt;br /&gt;    &lt;/code&gt;&lt;br /&gt;      Aquí utilicé sftp en lugar de scp porque para ficheros muy grandes se me cortaba.&lt;br /&gt;  &lt;/li&gt;  &lt;li&gt;Eliminar el volcado arriba.&lt;br /&gt;    &lt;code&gt;ssh.exec!("rm #{dh_project_url}")&lt;/code&gt;&lt;br /&gt;  &lt;/li&gt;  &lt;li&gt;Cargarlo en el servidor de desarrollo local y actualizar el número de versión del proyecto en la lista.&lt;br /&gt;    &lt;code&gt;&lt;br /&gt;      repositorio.load(:project_id =&gt; proyecto[:project_id], :folder =&gt; proyectos.dump_path)&lt;br /&gt;      # actualizar version&lt;br /&gt;      proyecto[:revision] = repositorio.last_revision(proyecto[:project_id])&lt;/code&gt;&lt;br /&gt;  &lt;/li&gt;  &lt;li&gt;La lista está actualizada está en un array, la volvemos a escribir en el fichero.&lt;br /&gt;    &lt;code&gt;&lt;br /&gt;      File.open(proyectos.list_path, 'w') do |f|&lt;br /&gt;        lista.each { |l| f &amp;lt;&amp;lt; l[:project_id] &amp;lt;&amp;lt; ':' &amp;lt;&amp;lt; l[:revision] &amp;lt;&amp;lt; "\n" }&lt;br /&gt;      end&lt;/code&gt;&lt;br /&gt;    &lt;/li&gt;  &lt;li&gt;Subir la nueva versión del proyecto actualizado a Dreamhost.&lt;br /&gt;    &lt;code&gt;ssh.scp.upload!(proyectos.list_path, '/home/cuentait7/etc')&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h4&gt;Notas&lt;/h4&gt;&lt;p&gt;En lugar de usar comandos de shell directamente, podría haber usado los subversion-bindings, disponible para varios lenguajes de programación entre ellos Ruby. El problema es que requiere que el usuario los tenga instalado en su sistema, por lo que opté por una solución autosuficiente. De hecho, las gemas de las que depende este módulo (net-ssh, net-scp, etc...) vienen también incluidas por la misma razón.&lt;/p&gt;&lt;p&gt;Ante todo soy pragmático, escribí estos scripts para usarlos en mi entorno de trabajo actual, por lo que hay muchas rutas a carpetas y ficheros en el código puestas a piñón fijo. A medida que necesite generalizarlo lo hiré haciendo, hasta entonces, ¿para qué preocuparse?&lt;/p&gt;&lt;p&gt;Tampoco hago manejo de excepciones. El usuario de los scripts se supone que es un programador o diseñador/maquetador que lanzará los comandos desde la consola de manera más o menos inteligente, y con la mínima capacidad de entender lo que pasa si se encuentra con algún error. Mi idea es que este conjunto de scripts evolucione hasta una interfaz web para que cualquiera de la empresa pueda lanzar los procesos de configuración de software necesarios para lanzar y desplegar un proyecto, será entonces cuando me preocupe de eso.&lt;/p&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;&lt;p&gt;Ya tengo un par de scripts para automatizar la tarea de sincronización de repositorios, y la infraestructura base (módulo Proyectos) para seguir desarrollando más. Como paranoico del backup, y no satisfecho con la redundancia obtenida hasta ahora, la siguiente tarea es hacer una exportación (código en limpio, sin los ficheros de control .svn) de la última versión de los proyectos para que entre en la copia de seguridad diaria de la empresa, tarea que por supuesto será automatizada también. ¡Pero eso lo dejo para el próximo artículo!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-4463710655452636297?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/4463710655452636297/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/02/automatizando-el-volcado-de.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4463710655452636297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/4463710655452636297'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/02/automatizando-el-volcado-de.html' title='Automatizando el volcado de repositorios'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-6646440312837550343</id><published>2010-01-29T15:08:00.001Z</published><updated>2010-02-18T11:08:24.918Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='servidor'/><category scheme='http://www.blogger.com/atom/ns#' term='proceso'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='instalacion'/><title type='text'>Estableciendo un repositorio subversion local como backup del principal</title><content type='html'>&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;Hemos estado siguiendo desde &lt;a href="http://eddyjosafat.blogspot.com/2009/12/arrancando.html"&gt;el primer artículo de este blog&lt;/a&gt;, el proceso que he seguido para ir modernizando los procesos productivos de la empresa donde trabajo y automatizar gradualmente el trabajo del día a día.&lt;/p&gt;&lt;p&gt;Tras &lt;a href="http://eddyjosafat.blogspot.com/2009/12/instalacion-del-servidor-de-desarrollo.html"&gt;instalar el servidor de desarrollo&lt;/a&gt;, denominado &lt;em&gt;Goldberg&lt;/em&gt;, lo configuramos para conectarse via ssh sin usar contraseña al servidor contratado por la empresa en Dreamhost.&lt;/p&gt;&lt;p&gt;Es en Dreamhost donde se encuentran los repositorios &lt;a href="http://subversion.tigris.org/"&gt;subversion&lt;/a&gt; de los proyectos. El control de versiones del código es esencial para la salud del programador; podría contar la infinidad de veces que eso me permitió deshacer algún cambio que produjo más problemas que soluciones, o que me permitió ahondar en la posible fuente de algunos bugs, así como permitir el trabajo compartido en el mismo código evitando las miradas asesinas porque alguién sobreescribió los cambios de otra persona (algo que suele suceder cuando todo el mundo trabaja sobre la misma carpeta compartida en los mismos ficheros).&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;p&gt;Nuestro objetivo es establecer la configuración de trabajo del control de versiones:&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;Repositorios principales situados en Dreamhost, para que cualquier miembro de la empresa pueda acceder desde cualquier punto (yo a veces trabajo desde casa, por ejemplo)&lt;/li&gt;  &lt;li&gt;Tener una réplica de esos repositorios en el servidor de desarrollo local, tanto como copia de seguridad como para si cae la conexión en Dreamhost poder seguir trabajando con el local.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Configuración de los repositorios en Dreamhost&lt;/h4&gt;&lt;p&gt;Crear un repositorio en Dreamhost es sencillo, no tienes más que utilizar la opción &lt;em&gt;Subversion&lt;/em&gt; del menú &lt;em&gt;Goodies&lt;/em&gt;, situado a la izquerda en el panel de control.&lt;/p&gt;&lt;p&gt;La convención que seguimos para la nomenclatura de los proyectos es asignarles un &lt;em&gt;id&lt;/em&gt; formado por un nombre fácil de recordar, que puede ser simple o formado por palabras compuestas, unidas con o sin carácter subrayado, somos bastante flexibles al respecto. Ese &lt;em&gt;id&lt;/em&gt; lo utilizaremos más adelante tanto para los repositorios locales como para los servidores virtuales del apache y la nomenclatura de las bases de datos.&lt;/p&gt;&lt;p&gt;Una vez creado el repositorio en Dreamhost, desde una consola seguimos la convención tradicional de crear tres carpetas principales, &lt;em&gt;trunk&lt;/em&gt;, &lt;em&gt;tags&lt;/em&gt; y &lt;em&gt;branches&lt;/em&gt;. El por qué de esas carpetas y cual es su uso determinado es un poco largo de explicar aquí, en algunos proyectos son útiles y en otros solo usarás el &lt;em&gt;trunk&lt;/em&gt; y no te complicarás la vida. A nivel personal, yo he tenido que usar el modelo completo de carpetas. Para una explicación más detalla, puedes googlear un poco o leerte el libro &lt;a href="http://www.pragprog.com/titles/svn2/pragmatic-version-control-using-subversion"&gt;&lt;em&gt;Pragmatic Version Control using Subversion, 2nd Edition&lt;/em&gt;&lt;/a&gt;. Aún así, si estás muy interesado en saber más, también puedes preguntarme ;-).&lt;/p&gt;&lt;p&gt;Cuando creamos el repositorio en Dreamhost, pasados unos minutos (depende de como esté de cargado el servidor) ya estará listo para su uso. Te llegará un mail notificándotelo. Para el siguiente paso, podemos hacerlo desde un acceso ssh al servidor de desarrollo (Goldberg), o desde nuestra propia máquina abriendo una ventana de terminal, en cuyo caso tenemos que tener instalado el Subversion en nuestra máquina, en el caso de trabajar en Linux instalar el paquete &lt;em&gt;subversion&lt;/em&gt;; en un Mac, podemos instalarlo a través del &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt;, en el caso de Windows, bueno, mejor cambia de entorno de desarrollo, para un programador no es el óptimo.&lt;/p&gt;&lt;p&gt;Asumiendo un proyecto que hemos identificado como &lt;em&gt;prueba&lt;/em&gt;, ejecutamos:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;  svn mkdir --message "Initial project layout" http://misvn.dreamhosters.com/prueba/trunk http://misvn.dreamhosters.com/prueba/branches http://misvn.dreamhosters.com/prueba/tags&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El mensaje de creación inicial puedes ponerlo en español, si quieres ("Estructura inicial del proyecto"), e incluso puedes poner lo que quieras, yo suelo seguir esa convención. Generalmente tanto los mensajes del repositorio como los comentarios del código suelo escribirlos en inglés, por eso de ser casi un estándar en el mundo de la programación en internet, aunque el código que muestre en este blog siempre estará en español.&lt;/p&gt;&lt;p&gt;A partir de aquí, lo siguiente que hacemos es hacer un checkout de la carpeta trunk, y añadir los ficheros iniciales del proyecto, pero todo el proceso de generación inicial del proyecto lo veremos en otro artículo, para centrarnos en el aspecto de la sincronización del control de versiones.&lt;/p&gt;&lt;h4&gt;Instalación y configuración del repositorio en el servidor de desarrollo local&lt;/h4&gt;&lt;p&gt;El Subversion puede utilizarse como servidor directamente, por medio del proceso svnserve, pero ya que tenemos un Apache instalado es más cómodo y práctico utilizar éste para recibir las peticiones.&lt;/p&gt;&lt;p&gt;Si has seguido la serie de artículos desde el &lt;a href="http://eddyjosafat.blogspot.com/2009/12/arrancando.html"&gt;principio&lt;/a&gt;, ya habrás instalado los paquetes necesarios, si no, has de instalar el servidor Subversion y la librería necesaria para servir los repositorios a través del Apache. En cualquier caso, el comando para hacerlo sería:&lt;/p&gt;&lt;code&gt;sudo apt-get install subversion libapache2-svn&lt;/code&gt;&lt;br /&gt;&lt;p&gt;A continuación, creamos la carpeta donde se alojarán los repositorios locales:&lt;/p&gt;&lt;code&gt;sudo mkdir /var/subversion&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Para cada proyecto, crearemos el repositorio, siguiendo con el ejemplo de nuestro proyecto &lt;em&gt;prueba&lt;/em&gt;:&lt;/p&gt;&lt;code&gt;sudo svnadmin create /var/subversion/prueba&lt;br /&gt;sudo chown -R www-data:www-data /var/subversion/prueba&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Hay que habilitar cada usuario y asignarle una contraseña (ejemplo para el usuario &lt;em&gt;eddy&lt;/em&gt;):&lt;/p&gt;&lt;code&gt;sudo htpasswd -c /etc/subversion/passwd eddy&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Por último, hay que editar el fichero &lt;em&gt;/etc/apache2/apache2.conf&lt;/em&gt; y añadir lo siguiente (tras lo cual reiniciaremos el Apache):&lt;/p&gt;&lt;code&gt;&amp;lt;Location /svn&gt;&lt;br /&gt;DAV svn&lt;br /&gt;SVNParentPath /var/subversion&lt;br /&gt;SVNListParentPath On&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthName "Texto que quieras aquí"&lt;br /&gt;AuthUserFile /etc/subversion/passwd&lt;br /&gt;&amp;lt;limitexcept GET PROPFIND OPTIONS REPORT&gt;&lt;br /&gt;Require valid-user&lt;br /&gt;&amp;lt;/LimitExcept&gt;&lt;br /&gt;&amp;lt;/Location&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Una vez se hayan importado los repositorios, se puede conectar desde cualquier máquina cliente usando como url http://goldberg/svn/prueba&lt;/p&gt;&lt;h4&gt;Volcado de repositorios desde Dreamhost a Goldberg&lt;/h4&gt;&lt;p&gt;Vamos a conectarnos al servidor remoto (Dreamhost) para volcar los repositorios, luego los bajaremos via sftp y los cargaremos. Veremos primero la forma manual de hacerlo, y en el próximo artículo veremos un pequeño script en Ruby que nos automatizará esta tarea.&lt;/p&gt;&lt;p&gt;Lanzaremos una terminal para ejecutar los siguientes comandos:&lt;/p&gt;&lt;code&gt;ssh nuestrousuario@nuestroservidor.dreamhost.com&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Una vez conectados a Dreamhost, para cada proyecto volcamos su repositorio en un fichero. Para nuestro proyecto denominado &lt;em&gt;prueba&lt;/em&gt;:&lt;/p&gt;&lt;code&gt;svnadmin dump svn/prueba &gt; prueba.svndump&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El nombre del fichero no tiene por qué acabar en &lt;em&gt;.svndump&lt;/em&gt;, esa es una convención que sigo yo. Por otro lado, comentar que este comando vuelca &lt;strong&gt;todas&lt;/strong&gt; las revisiones del proyecto. Es más conveniente volcar solo las revisiones efectuadas posteriormente a nuestro último volcado, ya que esta es una operación que haremos periódicamente, utilizando para ello los modificadores al comando dump, &lt;em&gt;--incremental&lt;/em&gt; y &lt;em&gt;--revision &amp;lt;num&gt;:&amp;lt;num&gt;&lt;/em&gt;, donde &lt;em&gt;num&lt;/em&gt; es el número de revisión (inicial y final). De esto hablaré en el próximo artículo cuando veamos el script para realizar esto automáticamente.&lt;/p&gt;&lt;p&gt;Una vez generados los volcados, los descargamos por sftp en una carpeta de Goldberg. Accedemos via ssh a &lt;em&gt;Goldberg&lt;/em&gt; y accedemos a la carpeta donde hemos descargado los ficheros volcados, y para cada uno de ellos lanzamos el siguiente comando para cargarlo en nuestro repositorio local. En el caso del proyecto &lt;em&gt;prueba&lt;/em&gt;:&lt;/p&gt;&lt;code&gt;svnadmin load /var/subversion/prueba &amp;lt; prueba.svndump&lt;/code&gt;&lt;br /&gt;&lt;p&gt;El comando svnadmin load carga un fichero de volcado de un repositorio en el repositorio local.&lt;/p&gt;&lt;h4&gt;Notas&lt;/h4&gt;&lt;p&gt;Existe otra forma de sincronizar los repositorios, mediante el &lt;em&gt;svnsync&lt;/em&gt;, que sincroniza automáticamente los cambios. El problema es que el repositorio local que se sincroniza es de solo lectura, y nosotros queríamos usar el local no solo como copia de seguridad, sino como repositorio secundario en caso de que fallase la conexión con el mundo exterior o incluso posteriormente si queremos usar solo el local.&lt;/p&gt;&lt;h4&gt;Conclusion&lt;/h4&gt;Una vez establecidos repositorios arriba y abajo, lo siguiente será automatizar el procedimiento de actualización de los repositorios, ya que realizar las cargas y volcados manualmente conlleva un coste muy alto: ¡imagina lanzar todos esos comandos aunque solo sea una vez al día cuando tienes 20 proyectos en marcha! Pero eso lo veremos &lt;a href="http://eddyjosafat.blogspot.com/2010/02/automatizando-el-volcado-de.html" title="Pulse para ver como automatizar la sincronización de repositorios con unos sencillos scripts de Ruby"&gt;en el próximo artículo&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-6646440312837550343?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/6646440312837550343/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/01/estableciendo-un-repositorio-subversion.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/6646440312837550343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/6646440312837550343'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/01/estableciendo-un-repositorio-subversion.html' title='Estableciendo un repositorio subversion local como backup del principal'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-1787872262612356206</id><published>2010-01-15T16:48:00.004Z</published><updated>2010-02-17T23:03:33.466Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='servidor'/><category scheme='http://www.blogger.com/atom/ns#' term='proceso'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='instalacion'/><title type='text'>Instalación del servidor de desarrollo (II)</title><content type='html'>&lt;h4&gt;Recapitulando&lt;/h4&gt;&lt;p&gt;&lt;a href="http://eddyjosafat.blogspot.com/2009/12/instalacion-del-servidor-de-desarrollo.html"&gt;En el artículo anterior&lt;/a&gt;, iniciamos la instalación del servidor de desarrollo con la distribución Linux Ubuntu Server 8.04. Realizamos una instalación básica, añadiendo los paquetes fundamentales que necesitamos y creamos las cuentas de usuario.&lt;/p&gt;&lt;p&gt;A continuación es necesario conectar el servidor con su entorno; por un lado necesitamos que se comunique con el servidor de la empresa en Dreamhost y por otro hay que facilitar el acceso al espacio de trabajo en el servidor a los distintos usuarios de la empresa.&lt;/p&gt;&lt;h4&gt;Objetivos&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Configurar el servidor de desarrollo ( &lt;i&gt;Goldberg&lt;/i&gt;) para que se conecte via ssh con Dreamhost sin necesidad de preguntar por la contraseña. Imprescindible para que los scripts que automatizan las tareas no requieran la intervención del usuario.&lt;/li&gt;&lt;li&gt;Permitir a los usuarios trabajar en sus respectivas carpetas alojadas en Goldberg de manera transparente al sistema operativo que estén utilizando en sus máquinas cliente.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id="genera_key_rsa"&gt;Conexión con Dreamhost&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Accedemos via ssh a &lt;i&gt;Goldberg&lt;/i&gt;, entramos como un usuario cualquiera (de ahora en adelante usaremos &lt;i&gt;eddy&lt;/i&gt; en los ejemplos), y ejecutamos:&lt;/li&gt;&lt;/ul&gt;&lt;code&gt;&lt;br /&gt;ssh-keygen -t rsa&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Pulsar Enter como respuesta a las diferentes preguntas. Una vez generado, tal como configuramos el servidor &lt;a href="http://eddyjosafat.blogspot.com/2009/12/instalacion-del-servidor-de-desarrollo.html"&gt;en el artículo anterior&lt;/a&gt;, todos los ficheros creados desde cualquier usuario adquieren como grupo propietario &lt;i&gt;www-data&lt;/i&gt;, y esto no lo consiente el agente ssh para el fichero de configuración, por lo que habremos de cambiar el grupo y hacer:&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;code&gt;&lt;br /&gt;chgrp eddy .ssh/config&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El paso anterior genera una clave pública que debemos copiar a dreamhost, con el comando (sustituir los datos de acceso a dreamhost por los correspondientes en el caso particular de cada uno):&lt;/li&gt;&lt;/ul&gt;&lt;code&gt;&lt;br /&gt;scp /home/eddy/.ssh/id_rsa.pub cuentadeusuario@greene.dreamhost.com:~&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Ahora conectamos con dreamhost para realizar las operaciones necesarias para habilitar la clave pública:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;ssh&amp;nbsp;cuentadeusuario@greene.dreamhost.com&lt;br /&gt;mkdir .ssh&lt;br /&gt;chmod 700 .ssh&lt;br /&gt;cat id_rsa.pub &amp;gt; .ssh/authorized_keys&lt;br /&gt;chmod 600 .ssh/authorized_keys&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Ahora ya podemos conectar desde &lt;i&gt;Goldberg&lt;/i&gt; sin usar contraseña, añadiendo la opción &lt;i&gt;-i /home/eddy/.ssh/id_rsa&lt;/i&gt; a los comandos ssh y scp.&lt;/p&gt;&lt;p&gt;Para ver más información sobre el acceso ssh, puedes consultar &lt;a href="https://help.ubuntu.com/8.04/serverguide/C/openssh-server.html"&gt;la guía del servidor ubuntu&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Hay que observar que esta forma de acceder no es muy segura porque estamos usando el ssh sin contraseñas de ningún tipo. Una forma más segura es usando el ssh-agent, aunque personalmente siempre lo he considerado un poco coñazo. Puedes ver como hacerlo &lt;a href="http://mah.everybody.org/docs/ssh"&gt;en este artículo&lt;/a&gt;.&lt;/p&gt;&lt;h4&gt;Compartir carpetas para usuarios con Linux&lt;/h4&gt;&lt;p&gt;Para compartir las carpetas de cada usuario en Goldberg usamos el protocolo NFS. Primero instalamos en Goldberg lo necesario:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo apt-get install nfs-kernel-server&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Luego editamos (en &lt;i&gt;Goldberg&lt;/i&gt;) el fichero &lt;i&gt;/etc/exports&lt;/i&gt; y añadimos al final la línea: &lt;i&gt;/home *(rw,sync,no_root_squash)&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Reiniciamos el servidor nfs:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo /etc/init.d/nfs-kernel-server restart&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;En la máquina de cada usuario, los pasos a seguir son, primero, instalar el paquete nfs caso de no estar instalado:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo apt-get install nfs-common&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;A continuación editamos el fichero &lt;i&gt;/etc/fstab&lt;/i&gt; para añadir el nombre de la carpeta en el servidor y el nombre de la carpeta donde se van a visualizar lo compartido en la máquina cliente (en el ejemplo uso el nombre de dominio local usado internamente, y como usuario de ejemplo utilizo &lt;i&gt;eddy)&lt;/i&gt;:&lt;br /&gt;&lt;/p&gt;&lt;code&gt;&lt;br /&gt;goldberg.it7:/home/eddy /home/eddy/goldberg nfs rsize=8192, timeo=14, intr&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Creamos la carpeta en la máquina cliente:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;mkdir &amp;nbsp;/home/eddy/goldberg&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Y por último montamos la carpeta, la forma más cómoda es dando la orden para montar todo lo que está indicado en el fichero &lt;i&gt;fstab&lt;/i&gt;:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo mount -a&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;En Linux, los usuarios tienen un id de usuario y otro de grupo, ambos numéricos. Se denominan &lt;i&gt;uid&lt;/i&gt; y &lt;i&gt;gid&lt;/i&gt;. Para que no haya problemas de permisos al &amp;nbsp;acceder desde la máquina cliente a la carpeta compartida, el &lt;i&gt;uid&lt;/i&gt;/&lt;i&gt;gid&lt;/i&gt; debe ser el mismo en ambas máquinas.&lt;/p&gt;&lt;p&gt;Para asegurarnos de ello, consultaremos el fichero &lt;i&gt;/etc/passwd &lt;/i&gt;de ambas máquinas,&amp;nbsp;donde veremos al lado del nombre de usuario el numerito en cuestión. Tenemos que hacer que coincidan en ambas máquinas, y en aquella donde lo hayamos cambiado, hay que volver a asignar esos ficheros al usuario con el nuevo&amp;nbsp;&lt;i&gt;uid/gid.&amp;nbsp;&lt;/i&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Hay dos formas de hacerlo:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Si el cambio lo hacemos en &lt;i&gt;Goldberg&lt;/i&gt;, y existen otros usuarios creados con permiso para ejecutar órdenes como root (&lt;i&gt;sudo&lt;/i&gt;), entramos como uno de ellos y ejecutamos:&lt;/li&gt;&lt;/ul&gt;&lt;code&gt;&lt;br /&gt;sudo chown -R eddy:eddy /home/eddy&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Si el cambio lo hacemos en la máquina cliente, donde probablemente seamos el único usuario, arrancamos la sesión en modo de entrada directa como root y sin contraseña para poder ejecutar la orden vista anteriormente. En el caso de una Ubuntu, supone seleccionar en el arranque entrar en &lt;i&gt;Terminal a prueba de fallos&lt;/i&gt;. Gracias a &lt;a href="http://www.facebook.com/profile.php?id=1457138153"&gt;David&lt;/a&gt; por este último apunte.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Es muy importante tener en cuenta que una vez que hacemos el cambio del uid/gid en el fichero de configuración, perderemos la capacidad de hacer sudo, por lo que en &lt;i&gt;Goldberg&lt;/i&gt;&amp;nbsp;debería haber otro usuario con capacidad de hacer sudo o bien en la distro de Linux utilizada en la máquina de cliente debe existir una opción para entrar directamente como root sin contraseña.&lt;/p&gt;&lt;h4&gt;Compartir carpetas para usuarios con Windows y Mac OS X&lt;/h4&gt;&lt;p&gt;Se realiza la exportación utilizando la aplicación &lt;a href="http://www.samba.org/"&gt;Samba&lt;/a&gt;. Este paquete lo seleccionamos en la instalación inicial del servidor de desarrollo, &lt;a href="http://eddyjosafat.blogspot.com/2009/12/instalacion-del-servidor-de-desarrollo.html"&gt;como vimos en la entrada anterior de este blog&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Primero, accedemos a &lt;i&gt;goldberg&lt;/i&gt;&amp;nbsp;desde una terminal, y por si cometemos algun error, copiamos el fichero original de configuración con el comando:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.original&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Una vez hecho esto, procedemos a realizar los siguientes cambios en &lt;i&gt;/etc/samba/smb.conf:&lt;/i&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;sustituir &lt;i&gt;workgroup = WORKGROUP&lt;/i&gt; por &lt;i&gt;workgroup = IT7&lt;/i&gt; (o el usado en la red local de Windows donde estemos realizando el despliegue).&lt;/li&gt;&lt;li&gt;sustituir &lt;i&gt;wins server = w.x.y.z&lt;/i&gt; por &lt;i&gt;wins server = 192.168.50.11&lt;/i&gt; (o la ip usada en tu red local por el servidor de dominio de windows)&lt;/li&gt;&lt;li&gt;En la sección &lt;i&gt;[homes]&lt;/i&gt;, descomentar todas las líneas (eliminar el ;) y sustituir &lt;i&gt;browseable = no&lt;/i&gt; por &lt;i&gt;browseable = yes&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;read only = yes&lt;/i&gt; por &lt;i&gt;read only = no&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;create mask = 0700&lt;/i&gt; por &lt;i&gt;create mask = 0775&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;directory mask = 0700&lt;/i&gt; por &lt;i&gt;directory mask = 0755&lt;/i&gt;&lt;/li&gt;&lt;li&gt;En la sección &lt;i&gt;[global]&lt;/i&gt; añadir las líneas:&lt;/li&gt;&lt;li&gt;&lt;i&gt;dos charset = UTF8&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;unix charset = UTF8&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;display charset = UTF8&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Tras esto, guardar el fichero y añadir las contraseñas samba de cada usuario con:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo smbpasswd -a.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Aparece un prompt pidiendola, introducimos la misma que tiene el usuario en &lt;i&gt;Goldberg&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;Los usuarios de Windows y Mac no tienen más que navegar por el Entorno de Red hasta llegar al servidor &lt;i&gt;Goldberg&lt;/i&gt;, al entrar veremos nuestra carpeta de usuario, y tras introducir el usuario y contraseña que tenemos asignados ya podremos usar la carpeta con normalidad.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;Notas:&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Otra opción hubiera sido tratar de conectar &lt;i&gt;Goldberg&lt;/i&gt;&amp;nbsp;al servicio Active Directory del servidor Windows presente en la red local, pero hubiera sido mucho más complejo, así que opté por una opción más sencilla.&lt;/li&gt;&lt;li&gt;Es bastante probable que algunas de las opciones indicadas en el &lt;i&gt;smb.conf&lt;/i&gt; más arriba no sean necesarias. Mi fuerte no es la administración de servidores, así que opté por lo que vi que funcionaba sin analizarlo demasiado: si funciona, me vale.&lt;/li&gt;&lt;li&gt;Conecto el Mac OS X via Samba en lugar de NFS (que hubiera sido más natural al ser sistemas basados en UNIX) porque me daba bastantes problemas. Si alguien tiene información de como hacer la conexión de esa manera de forma sencilla, rápida y fiable, bienvenida sea!&lt;/li&gt;&lt;li&gt;El Mac OS X cuando trabaja con archivos montados en un volumen que no está formateado en el sistema HFS (sistema nativo de los MAC) crea unos meta-archivos llamados igual que el archivo con el que trabajemos pero anteponiendoles &lt;i&gt;._ . &lt;/i&gt;Si queremos evitar ese comportamiento, deberemos desactivarlo. Desconozco como hacerlo a nivel global (cuando trabajas con cualquier programa), pero para hacerlo con el &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; (mi editor de código favorito) usaremos la siguiente orden desde una ventana de terminal en nuestro Mac:&lt;/li&gt;&lt;/ul&gt;&lt;code&gt;&lt;br /&gt;defaults write com.macromates.textmate OakDocumentDisableFSMetaData 1&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Conclusión&lt;/h4&gt;&lt;p&gt;Ya tenemos el servidor de desarrollo preparado para que los usuarios trabajen en él, al igual que para conectarse con el servidor externo donde residen los proyectos y el software de control de versiones. &lt;a href="http://eddyjosafat.blogspot.com/2010/01/estableciendo-un-repositorio-subversion.html"&gt;El próximo paso&lt;/a&gt; consiste en instalar el Subversion, de tal forma que en el entorno local tendremos una réplica de los repositorios de código alojados en el servidor externo (Dreamhost).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-1787872262612356206?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/1787872262612356206/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2010/01/instalacion-del-servidor-de-desarrollo.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/1787872262612356206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/1787872262612356206'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2010/01/instalacion-del-servidor-de-desarrollo.html' title='Instalación del servidor de desarrollo (II)'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-8599565258324924124</id><published>2009-12-15T19:18:00.010Z</published><updated>2010-01-24T00:04:57.751Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='servidor'/><category scheme='http://www.blogger.com/atom/ns#' term='proceso'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='instalacion'/><title type='text'>Instalación del servidor de desarrollo (I)</title><content type='html'>&lt;h4&gt;Oh My God!&lt;/h4&gt;&lt;p&gt;Aunqué &lt;a href="http://eddyjosafat.blogspot.com/2009/12/arrancando.html"&gt;hablé a grandes rasgos&lt;/a&gt; del entorno del que parto a la hora de automatizar mía día a día, vamos a detallarlo un poco más.&lt;/p&gt;&lt;p&gt;Cuando llegué a la empresa donde trabajo actualmente, me encontré con el siguiente entorno de desarrollo:&lt;/p&gt;&lt;p&gt;2 PC haciendo de servidores:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;(&lt;i&gt;Serv1&lt;/i&gt;) Windows 2003 Server: Exchange, carpetas compartidas, Oracle, Copias de seguridad.&lt;/li&gt;&lt;li&gt;(&lt;i&gt;Serv2&lt;/i&gt;) Windows XP Profesional: WAMP (Apache, MySQL, PHP), carpetas web.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Todas las máquinas cliente corriendo Windows XP Profesional SP2. Los proyectos web se alojaban en &lt;i&gt;Serv2&lt;/i&gt;, en carpetas compartidas, y todo el mundo trabajaba directamente sobre ellos.&lt;/p&gt;&lt;p&gt;Esta configuración presentaba varios problemas:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;Serv2&lt;/i&gt;, al estar basado en un Windows XP no es muy estable, y cada vez que la máquina se reinicia por una actualización automática del sistema operativo hay que acceder físicamente a la máquina e iniciar sesión para que arranque el WAMP.&lt;/li&gt;&lt;li&gt;Los servidores de producción usados generalmente están basados en sistemas Linux, por lo que era más fácil encontrarse con sorpresas desagradables a la hora de realizar los despliegues por las diferencias entre ambos sistemas operativos.&lt;/li&gt;&lt;li&gt;Al trabajar sobre los mismos archivos, no pueden haber dos personas tocando lo mismo simultáneamente, además del riesgo de machacar el trabajo realizado por otro en ese mismo día sin darnos cuenta.&lt;/li&gt;&lt;li&gt;Al carecer de control de versiones, cada vez que se realizaba un cambio se corría el riesgo de estropear alguna parte del sistema (...y como tampoco realizaban &lt;a href="http://es.wikipedia.org/wiki/Desarrollo_guiado_por_pruebas"&gt;TDD -Test Driven Development-&lt;/a&gt;) y luego no poder volver a retroceder sin problemas al no recordar que partes de la &amp;nbsp;aplicación se habían tocado. Por otro lado esto siempre produce la proliferación de archivos tipo "miarchivo.php.bak", "miarchivo.php.old", "miarchivo.old2.php", etc... Habitual conglomerado de copias que no se sabe muy bien que pintan ahí ni cual es la razón de su existencia.&lt;/li&gt;&lt;li&gt;Todo el entorno de red, a nivel de DNS y demás, estaba pensado para máquinas cliente con Windows, pero yo uso Mac OS X, y posteriormente entró otro programador que usa Ubuntu, y ninguno de los dos teníamos ganas de pelearnos con el Active Directory de Microsoft, el Exchange y demás.&lt;/li&gt;&lt;li&gt;La información sobre los proyectos y el código se encontraban diseminadas en un amplio conjunto de ubicaciones distintas, siendo bastante complejo en ocasiones encontrar cualquier dato necesario.&lt;/li&gt;&lt;li&gt;Los desarrollos estaban basados en código propio, sin el uso de ningun framework estándar. Aunque el código cumplía su función (más o menos) era dificil de ampliar.&lt;/li&gt;&lt;li&gt;Se perdía mucho tiempo en tareas rutinarias, restando tiempo a profesionales veteranos para realmente concentrarse en las cosas importantes.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Primeras medidas a tomar&lt;/h4&gt;&lt;p&gt;En vista de la situación me formé un esquema a rasgos generales (&lt;a href="http://eddyjosafat.blogspot.com/2009/12/arrancando.html"&gt;comentado a grandes rasgos en el anterior artículo&lt;/a&gt;) y decidí que los primeros pasos serían:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Instalar un servidor de desarrollo basado en Linux.&lt;/li&gt;&lt;li&gt;Implantar el control de versiones en el flujo de trabajo habitual.&lt;/li&gt;&lt;li&gt;Concentrar la información de los proyectos en un único punto para facilitar su disponibilidad.&lt;/li&gt;&lt;li&gt;Comenzar a usar Rails para los proyectos con libertad de elección en cuanto a tecnología, y CakePHP (clon del rails) para aquellos donde estábamos limitados a usar PHP.&lt;/li&gt;&lt;li&gt;Contratar un servidor dedicado para el despliegue de las aplicaciones y tener mayor control sobre la tecnología usada. El alojamiento compartido está bien para el típico proyecto web, pero para temas más avanzados mejor tener toda la capacidad de decisión.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;En este artículo nos centraremos en el primer punto, aunque algunas de las decisiones a la hora de instalar el servidor vienen motivadas por las reflexiones y descubrimientos que veremos en próximos artículos donde abordaremos los otros objetivos.&lt;/p&gt;&lt;p&gt;Instalar un servidor de desarrollo basado en Linux&lt;/p&gt;&lt;p&gt;Los nombres de dominios y direcciones IP dependerán de cada caso. Yo utilizaré los usados en la empresa donde trabajo actualmente, &lt;a href="http://www.it7.info/"&gt;IT7&lt;/a&gt;&amp;nbsp;(aunque también colaboro con &lt;a href="http://www.solucionesavanzadascanarias.es/"&gt;SAC&lt;/a&gt; y &lt;a href="http://www.k-nabora.com/"&gt;K-Nábora&lt;/a&gt;), aunque cambiando las direcciones IP para no revelar la configuración exacta de la red interna.&lt;/p&gt;&lt;p&gt;Para la instalación inicial partimos de una Ubuntu 8.04 server LTS, &lt;a href="http://www.ubuntu.com/getubuntu/download-server"&gt;aunque se puede elegir alguna posterior&lt;/a&gt;. Tras arrancar el PC con el cd de la Ubuntu dentro, los pasos son:&lt;/p&gt;&lt;ol&gt;&lt;li&gt; Seleccionar idioma español.&lt;/li&gt;&lt;li&gt; Seleccionar instalar Ubuntu server.&lt;/li&gt;&lt;li&gt; Seleccionar España.&lt;/li&gt;&lt;li&gt; Seleccionar Sí ante la pregunta por el layout del teclado.&lt;/li&gt;&lt;li&gt; Presionar todas las teclas que va pidiendo y responder a las preguntas que hace sobre la presencia de determinadas teclas en el teclado.&lt;/li&gt;&lt;li&gt; Cuando pregunta nombre de la máquina, introducir goldberg&lt;/li&gt;&lt;li&gt; Seleccionar zona horaria.&lt;/li&gt;&lt;li&gt; En el particionado de discos, para no complicar la vida, seleccionar la opción Guiado - utilizar todo el disco&lt;/li&gt;&lt;li&gt; Elegir Si cuando pregunta si se desea escribir los cambios en el disco (formateado)&lt;/li&gt;&lt;li&gt; Crear cuenta de usuario. Introducir nombre completo, nombre de usuario y contraseña. Dejar la opción por defecto de No crear directorio cifrado.&lt;/li&gt;&lt;li&gt; Dejar en blanco la opción de usar proxy para obtener la información de paquetes.&lt;/li&gt;&lt;li&gt; Dejar opción por defecto de no realizar actualizaciones automáticas.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;A continuación y por comodidad, el programa de instalación nos permite instalar varios conjuntos de paquetes preseleccionados en función de nuestras necesidades.&lt;/p&gt;&lt;p&gt;Seleccionaremos los siguientes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;LAMP server: Apache 2, MySQL 5 y PHP 5.&lt;/li&gt;&lt;li&gt;Mail server: necesario para que nuestras aplicaciones y scripts de mantenimiento puedan enviar correos.&lt;/li&gt;&lt;li&gt;OpenSSH server: para poder acceder al sistema desde cualquier máquina cliente de la oficina.&lt;/li&gt;&lt;li&gt;DNS server: como veremos en próximos artículos, para acceder desde el navegador a los proyectos en los que trabajamos, usaremos direcciones del tipo &lt;i&gt;nombre de usuario.nombre de proyecto.it7 &lt;/i&gt;(por ejemplo eddy.laaldea.it7, dcabrera.laaldea.it7, etc...). Para ello las máquinas clientes tienen que conectarse a un servidor DNS que resuelva dichas direcciones, para lo cual usaremos este mismo servidor.&lt;/li&gt;&lt;li&gt;Samba file server: tras probar varias configuraciones de trabajo se encontró que la más cómoda era aquella donde los usuarios trabajaban sobre carpetas situadas en el propio servidor. Para clientes linux utilizaremos NFS, pero para máquinas Windows y Mac OS X accederemos por Samba.&lt;/li&gt;&lt;/ul&gt;Tras seleccionar lo visto anteriormente, continuamos con la instalación:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; Introducir contraseña root de mysql.&lt;/li&gt;&lt;li&gt; Dejar opción por defecto de correo denominada Sitio de Internet.&lt;/li&gt;&lt;li&gt; En la configuración del correo, cuando pregunta por el nombre del host, usar &lt;i&gt;goldberg.it7&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Tras esto nos pide que retiremos el CD y reiniciemos. Una vez reiniciado, entramos con la cuenta creada y ejecutamos:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo apt-get update&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;para actualizar la información de paquetes disponibles en los repositorios, y&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo apt-get upgrade&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;para actualizar los paquetes instalados. Es posible que se haya actualizado la imagen del kernel, por lo que ante la duda reiniciaremos el servidor.&lt;/p&gt;&lt;p&gt;Por comodidad utilizaremos el phpMyAdmin para gestionar el servidor MySQL, por lo que lo instalamos con&amp;nbsp;&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo apt-get install phpmyadmin&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;En la instalación del phpmyadmin, pregunta para que servidor ha de realizarse. &amp;nbsp;Seleccionaremos &lt;i&gt;apache2.&lt;/i&gt;&lt;br /&gt;Como veremos cuando hablemos de la implantación del control de versiones, usaremos el servidor Subversion de Dreamhost, pero para mayor seguridad y en caso de no disponer de conexión a éste, vamos a configurar un repositorio que replique el principal en esta máquina. Para ello instalaremos los paquetes necesarios:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo apt-get install subversion libapache2-svn&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Ahora hay que configurar la red. Durante la instalación, el programa habrá utilizado la opción de coger una dirección IP proporcionada por el router (DHCP). Aunque generalmente para una configuración de máquinas estable todas acabarán adoptando siempre las mismas direcciones, es mejor asegurarnos proporcionando una dirección IP fija al servidor. Para ello hay que editar el fichero donde se definen las interfaces de red. En mi caso, uso el editor vi.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo vi /etc/network/interfaces&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Si como hemos dicho, durante la instalación se usó DHCP para configurar la red, veremos algo como esto:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;# The primary network interface&lt;br /&gt;auto eth0&lt;br /&gt;iface eth0 inet dhcp&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Esta última línea se sustituye para asignar una ip fija dentro del rango asignado para esto dentro de la red interna. La configuración actual de &lt;i&gt;Goldberg&lt;/i&gt; queda como sigue (en sustitución de la línea mencionada):&lt;br /&gt;&lt;code&gt;&lt;br /&gt;iface eth0 inet static&lt;br /&gt;address 192.168.50.63&lt;br /&gt;netmask 255.255.255.0&lt;br /&gt;gateway 192.168.50.20&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;A continuación guardamos el fichero y editamos el fichero donde se indican los servidores de direcciones de nombre que utilizará &lt;i&gt;Goldberg. &lt;/i&gt;Éste va a ser el servidor DNS de la red interna, forwardeando las solicitudes de direcciones externas.&lt;/p&gt;&lt;p&gt;Como servidores adicionales DNS suelo usar los de Telefónica, por nada en especial, sencillamente porque de tanto configurar internet para familiares y amigos acabé aprendiéndome esas direcciones en concreto.&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo vi etc/resolv.conf&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Aquí pondremos (sustituyendo lo que haya)&lt;/p&gt;&lt;code&gt;&lt;br /&gt;nameserver 192.168.50.63&lt;br /&gt;nameserver 194.179.1.100&lt;br /&gt;nameserver 194.179.1.101&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Ahora hay que crear los usuarios del sistema. Para cada uno de ellos haremos:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo adduser&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Introducir contraseña, nombre y una vez creado procedemos con:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo adduser &lt;i&gt;nombre de usuario&lt;/i&gt; www-data&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;(por ejemplo &lt;i&gt;sudo adduser eddy www-data&lt;/i&gt;).&lt;/p&gt;&lt;p&gt;Con esto hemos añadido el usuario al grupo del servidor apache. Para los usuarios avanzados (generalmente los programadores) que requieran privilegios administrativos sobre el servidor, ejecutaremos&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo adduser &lt;i&gt;nombre de usuario &lt;/i&gt;admin&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;(por ejemplo &lt;i&gt;sudo adduser eddy admin&lt;/i&gt;).&lt;/p&gt;En un sistema Ubuntu, se crea una carpeta &lt;i&gt;home&lt;/i&gt; de la que cuelga una carpeta para cada usuario del sistema (&lt;i&gt;eddy&lt;/i&gt;, &lt;i&gt;dcabrera,&lt;/i&gt; etc.). Además, se crea un grupo de usuarios con el mismo nombre de usuario para cada uno de ellos.&lt;br /&gt;&lt;p&gt;En el sistema de permisos de Linux, por defecto se establece como propietario de la carpeta el usuario, y como grupo al que pertenece el grupo del usuario. Hay que cambiar el grupo e indicar que pertenece al grupo &lt;i&gt;www-data&lt;/i&gt;, que es el grupo al que pertenece el servidor Apache y así éste no tenga problemas a la hora de acceder a los archivos de trabajo de cada usuario. Además hay que fijar este grupo automáticamente para las nuevas carpetas y ficheros que se creen. Para ello, con cada usuario (utilizaré el usuario eddy para el resto de ejemplos):&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo chgrp -R www-data /home/eddy&lt;br /&gt;sudo chmod -R g+s /home/eddy&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Añadimos parámetros globales de permisos de ficheros, para ello editaremos los ficheros &lt;i&gt;/etc/profile&lt;/i&gt; y /&lt;i&gt;etc/apache2/envvars&lt;/i&gt; y en ambos incluiremos la línea&lt;/p&gt;&lt;code&gt;&lt;br /&gt;umask 002&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Y para finalizar por ahora, crearemos las carpetas para los scripts de automatización del día a día:&lt;/p&gt;&lt;code&gt;&lt;br /&gt;sudo mkdir /etc/scripts&lt;br /&gt;sudo mkdir /usr/local/bin/scripts&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Esta estructura es la utilizada a lo largo de los artículos, aunque tras terminar de leer &lt;i&gt;&lt;a href="http://www.pragprog.com/titles/bmsft/everyday-scripting-with-ruby"&gt;Everyday Scripting With Ruby&lt;/a&gt;&lt;/i&gt; decidí que más adelante y a medida que desarrolle scripts más complejos utilizaría una estructura más estándar tal como se propone en el capítulo 19 (A Polished Script).&lt;/p&gt;&lt;h4&gt;Donde estamos y hacia donde vamos&lt;/h4&gt;&lt;p&gt;Por el momento ya tenemos un servidor instalado, aunque tal como está configurado en este momento aún no podemos alojar ningún proyecto web.&lt;/p&gt;&lt;p&gt;&lt;a href="http://eddyjosafat.blogspot.com/2010/01/instalacion-del-servidor-de-desarrollo.html"&gt;En el próximo artículo&lt;/a&gt;, prepararemos el servidor para conectar con el de Dreamhost y para compartir las carpetas &lt;i&gt;home&lt;/i&gt; de cada usuario por la red (vía Samba y NFS) y acceder a ellas desde las máquinas cliente.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-8599565258324924124?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/8599565258324924124/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2009/12/instalacion-del-servidor-de-desarrollo.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/8599565258324924124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/8599565258324924124'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2009/12/instalacion-del-servidor-de-desarrollo.html' title='Instalación del servidor de desarrollo (I)'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6747698170585092034.post-5433549022653562766</id><published>2009-12-02T15:43:00.006Z</published><updated>2010-06-21T14:54:39.241+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='proceso'/><title type='text'>Arrancando</title><content type='html'>&lt;p&gt;Recientemente comencé un trabajo nuevo, y nada más llegar me encontré con lo que me encuentro por lo general en todas las empresas del sector web aquí en Canarias: un entorno de desarrollo ineficiente, donde se realizaban un montón de tareas repetitivas manualmente, todo el mundo trabajaba sobre la misma copia de código ubicada en un servidor central (Windows) y la información sobre los proyectos se hallaba dispersa (carpetas de claves, carpetas de proyectos, correos de usuarios, etc...).&lt;/p&gt;&lt;p&gt;Todo el código era desarrollado en PHP; todos los proyectos llevaban un gestor desarrollado por la propia empresa, cuya interfaz es muy buena, con una usabilidad excelente, pero la implementación no permite su generalización para cualquier proyecto sin tener que modificar un montón de ficheros a mano.&lt;/p&gt;&lt;p&gt;Me gusta hacer bien mi trabajo, que mi tiempo sea productivo en lugar de perderlo haciendo tareas que podría hacer un mono entrenado. He comprobado las bondades del desarrollo agil, el control de versiones y el TDD (Test Driven Development); he paladeado las mieles del trabajo creativo mientras una serie de scripts se encargan de realizar las tareas rutinarias, asi que me propuse realizar cambios en todo el sistema productivo de la empresa.&lt;/p&gt;&lt;p&gt;Me fijé como objetivo final trabajar en un entorno&amp;nbsp;de desarrollo robusto, seguro y flexible, en el que pueda ser feliz trabajando y mejore la productividad de la empresa. Esto último le encantó a mis empleadores, por lo que he tenido via libre a la hora de implementar los cambios.&lt;/p&gt;&lt;p id="objetivos"&gt;Para ello los pasos a seguir son:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;instalar un servidor de desarrollo basado en un SO más estable (Linux).&lt;/li&gt;&lt;li&gt;contratar un servidor dedicado para en la medida de lo posible alojar los trabajos realizados y no estar con las miserias y desventuras de los hosting compartidos.&lt;/li&gt;&lt;li&gt;implementar un workflow basado en control de versiones.&lt;/li&gt;&lt;li&gt;implantar metodologías ágiles ("Getting Real").&lt;/li&gt;&lt;li&gt;implantar el desarrollo orientado a tests (TDD).&lt;/li&gt;&lt;li&gt;automatizar &amp;nbsp;todas las tareas rutinarias.&lt;/li&gt;&lt;li&gt;progresivamente crear un sistema generador de proyectos para realizar con él las "típicas webs" y dejar el esfuerzo mental para los proyectos realmente interesantes.&lt;/li&gt;&lt;li&gt;para las aplicaciones basadas en PHP, implementar el CakePHP, framework clon del Rails que me resulta cómodo por mi afinidad con el RoR.&lt;/li&gt;&lt;li&gt;desarrollar los proyectos en Ruby on Rails preferentemente, sin descartar en cada momento usar otras tecnologías si son más adecuadas.&lt;/li&gt;&lt;li&gt;cambiar la relación de la empresa con los clientes.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;En sucesivos artículos, iremos viendo todos los pasos que he ido (estoy) dando para cumplir estos objetivos y así automatizar mi dia a día, dedicando mi esfuerzo mental a la parte más compleja y/o creativa de la programación.&lt;/p&gt;&lt;p&gt;Espero que estas recetas puedan automatizar tu día a día también.&lt;/p&gt;&lt;p&gt;Siguiente:&amp;nbsp;&lt;a href="http://eddyjosafat.blogspot.com/2009/12/instalacion-del-servidor-de-desarrollo.html"&gt;Instalación del servidor de desarrollo (I)&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6747698170585092034-5433549022653562766?l=eddyjosafat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eddyjosafat.blogspot.com/feeds/5433549022653562766/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://eddyjosafat.blogspot.com/2009/12/arrancando.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/5433549022653562766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6747698170585092034/posts/default/5433549022653562766'/><link rel='alternate' type='text/html' href='http://eddyjosafat.blogspot.com/2009/12/arrancando.html' title='Arrancando'/><author><name>Eddy Josafat</name><uri>http://www.blogger.com/profile/05303996733740234331</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_O8P6K77Brzw/Spfc62UFQCI/AAAAAAAAAAM/2xax8NbGzdM/S220/foto-perfil.jpg'/></author><thr:total>0</thr:total></entry></feed>
