sábado, 31 de julio de 2010

Barajitas premiadas (#13) - MySQL Sandbox

Esta herramienta me parece una excelente alternativa para hacer pruebas con MySQL. Les cuento para qué la utilicé para que se hagan una idea de su utilidad.

Por cuestiones de trabajo necesitaba hacer pruebas con varias bases de datos MySQL, esto porque tenemos un entorno con replicación maestro-esclavo bien diverso.

Primero pensé en montar varias máquinas virtuales en mi computador -con Ubuntu- pero éste tiene serias limitaciones de memoria y procesamiento, por lo que descarté VMWare y VirtualBox. Luego pensé en instalar una máquina virtual más liviana que compartiera funcionalidades del kernel, algo tipo Zonas de Solaris, conseguí Linux-VServer pero lo encontré bastante limitante, tuve que recurrir a un montón de artilugios con IPTables para lograr que medio funcionara.

Entonces... Pensé en instalar varias instancias de la base de datos en mi máquina... Cuando comencé a configurar cada una comenzó el karma, por lo engorroso de sus archivos de configuración. Y de repente, se hizo la luz! Conseguí el MySQL Sandbox y listo!

Esta herramienta permite configurar tantas instancias de MySQL como se desee a partir de sus binarios. Por ejemplo:

$ make_sandbox mysql.tar.gz
$ ~/sandbox/MY_SANDBOX/start_all
$ mysql -u root --password=msandbox -h localhost --port=17050 &
$ mysql -u root --password=msandbox -h localhost --port=17051 &
$ mysql -u root --password=msandbox -h localhost --port=17051 &

Enjoy! Siempre puede ver los archivos de configuración de cada instancia (my.cnf) dentro de las carpetas correspondientes a cada nodo, dentro del sandbox.


PHP Auto Conf

Perdonen que he andado un poco perdido con el blog, he estado full con el desarrollo de una herramienta para automatizar tareas utilizando scripts escritos en PHP, la he llamado phpautoconf.

Pretendo que facilite la automatización de tareas, sobre todo para sysadmins. Espero escribirles pronto al respecto, de momento comenzaré a colocar todo en GitHub; ya les avisaré!

jueves, 29 de julio de 2010

Cómo hacer que un script se ejecute al iniciar/reiniciar/apagar el sistema

Este artículo me parece que explica de forma sucinta y excelente cómo hacer que un script se ejecute al iniciar/reiniciar/apagar el sistema. Además, siguiendo el método mencionado dejaremos un script en init.d que podría ser utilizado durante una sesión para iniciar o detener el servicio.

Making scripts run at boot time with Debian

lunes, 26 de julio de 2010

Barajitas premiadas (#12) - tail

Del artículo Chat p2p Netcat cifrado con OpenSSL espero sacar varias barajitas...

La primera, tiene que ver con el comando tail. Este comando permite ver las últimas líneas de un archivo. Por ejemplo, a continuación se mostrarán las últimas 20 líneas del archivo de logs del sistema; muy útil para obtener información cuando se adjunta algún equipo al computador (ver también dmesg).

# tail -20 /var/log/messages

Ahora, este comando posee una opción poderosa que permite ver el contenido de un archivo en línea, de forma sigilosa (opción -f), es decir, conforme este cambie se irán mostrando sus registros... Esto es súper útil para chequear logs del sistema (Ej. logs de un servidor HTTP).

#  tail -f /var/log/apache2/error.log

Y para finalizar el artículo, hay veces en las que deseo realizar una tarea para cada nuevo registro escuchado por el tail, para ello puedo utilizar el comando read dentro de un bucle de la siguiente forma:

#  tail -f /var/log/apache2/error.log | while read -r line; do php procesador.php $line; done

El comando mostrado arriba ejecutará el script procesador.php para cada nueva línea dentro del archivo /var/log/apache2/error.log. Podríamos suponer que el script se conecta a una BD y deja el nuevo registro en ella.


domingo, 25 de julio de 2010

Chat p2p Netcat cifrado con OpenSSL

Este artículo lo escribí pensando en incluir un canal cifrado para el chat p2p que comenté días atrás en: La navaja suiza.

Quería incluir un cifrado sencillo simétrico (utilizando DES) con OpenSSL y además quería hacerlo para cada entrada enviada entre Cliente y Servidor y no por todo un bloque.

Como me gustó tanto este ejercicio, creé los siguientes scripts (que de preferencia recomiendo ejecutar en el orden en que son presentados):
  1. start_server.sh Inicia el netcat como escucha y envía la salida a un archivo (OUTPUT_FILE). Podrá notar que siempre que se corre este script, es vaciado el contenido del OUTPUT_FILE
  2. start_client.sh Comienza la lectura sigilosa de un archivo (de tipo PIPE*) utilizando el comando tail -f. Cada nueva entrada en este archivo (INPUT_FILE) será enviada al servidor haciendo uso de netcat.
  3. receiver.sh Este script y el mencionado seguidamente, son los encargados de tomar las entradas o salidas de netcat y cifrarlas o descifrarlas. En este caso, este script toma lo que ha recibido el servidor (OUTPUT_FILE) y lo descifra (puesto que dentro del mismo quedará el contenido cifrado)
  4. send.sh Este script permite enviar un mensaje desde el cliente al servidor, para lo cual utiliza el archivo INPUT_FILE, donde coloca el mensaje cifrado.

*: En el siguiente enlace podrá conseguir información bastante útil acerca de archivos FIFO.

En definitiva, los scripts start_server.sh y start_client.sh establecen la conexión TCP a través de netcat. Luego, los scripts send.sh y receiver.sh cifran y descifran los mensajes que viajarán entre cliente y servidor. Para utilizar estos scripts correctamente, deberá tener en el cliente los archivos start_client.sh y send.sh, y en el servidor, los archivos start_server.sh y receiver.sh.

Los scripts:

Script: start_server.sh
#!/bin/bash
OUTPUT_FILE='output'
PORT='1234'

if [ $# -eq 2 ]
then
        OUTPUT_FILE=$1
        PORT=$2
elif [ $# -gt 0 ]
then
        echo "Usage: start_server.sh [output_file port]"
        exit
fi

cat /dev/null > $OUTPUT_FILE && netcat -l -p $PORT > $OUTPUT_FILE

Script: start_client.sh.
#!/bin/bash
SERVER='localhost'
PORT='1234'
INPUT_FILE='input'

if [ $# -gt 3 ]
then
        echo "Usage: start_client.sh [server] [port] [input_file]"
        exit
else
        if [ $1 ]; then SERVER=$1; fi
        if [ $2 ]; then PORT=$2; fi
        if [ $3 ]; then INPUT_FILE=$3; fi
fi

if [ -p $INPUT_FILE ]
then
        tail -f $INPUT_FILE | netcat $SERVER $PORT
else
        echo "$INPUT_FILE isn't a pipe file. First, you may want to run: mkfifo $INPUT_FILE"
fi

Script: receiver.sh
#!/bin/bash
PASSWORD='1234'
OUTPUT_FILE='output'

if [ $# -gt 2 ]
then
        echo "Usage: receiver.sh [output_file] [password]"
        exit
else
        if [ $1 ]; then PASSWORD=$1; fi
        if [ $2 ]; then OUTPUT_FILE=$2; fi
fi

tail -f $OUTPUT_FILE | \
        while read -r line
        do
                echo $line | openssl enc -d -a -des3 -pass pass:$PASSWORD
        done

Script: send.sh
#!/bin/bash
PASSWORD='1234'
INPUT_FILE='input'

if [ $# -lt 1 ] || [ $# -gt 3 ]
then
        echo "Usage: send.sh message [password] [input_file]"
        exit
else
        if [ "$1" ]; then MESSAGE=$1; fi
        if [ $2 ]; then PASSWORD=$2; fi
        if [ $3 ]; then INPUT_FILE=$3; fi
fi

if [ -p $INPUT_FILE ]
then
        echo $MESSAGE | openssl enc -e -a -salt -des3 -pass pass:$PASSWORD -out $INPUT_FILE
else
        echo "$INPUT_FILE isn't a pipe file. Probably you don't have a server_client running"
fi

Un ejemplo:

En una consola (Consola #1 - Servidor):
$ ./start_server.sh &
$ ./receiver.sh

En otra consola (Consola #2 - Cliente):
$ mkfifo input
$ ./start_client.sh &
$ ./send.sh "primer envío"



viernes, 23 de julio de 2010

Barajita premiada (#11) - ejecutar un comando para cada línea de un archivo

Típico que tenemos en algún archivo un listado de nombres y queremos ejecutar un comando para cada una de las líneas del mismo. Por ejemplo: supongamos que tengo un directorio con un montón de archivos, pero quiero borrar sólo un subconjunto de los contenidos en éste. Entonces, podría copiar los nombres (uno por línea) dentro de un archivo y pedir que se ejecute el comando rm por cada línea... Esto no tiene sentido si el subconjunto está compuesto por 5 nombres o menos, pero si son más, seguro que sería de utilidad algo como:

$ for i in `seq 1 100`; do touch $i; done # generando archivos vacios
$ cat a_borrar # mostrando el archivo que contiene la lista de elementos a borrar
22
3
4
65
6
12
45
90
32
76
48
98
32
$ for i in `cat a_borrar`; do rm $i; done # borrando los archivos especificados



miércoles, 21 de julio de 2010

Barajitas premiadas (#10) - countries, states, cities

No puedo dejar pasar esta barajita porque precisamente estaba buscando al respecto y conseguí unos excelentes enlaces, y antes de que se me olvide...

Típico de un sistema... dos o tres combos dependientes uno del otro donde se cargarán paises, estados y ciudades (Ej. Fulano vive en Venezuela->Miranda->San Antonio de Los Altos) ¿el problema? los datos...

De dónde saco los datos más actualizados, pues por supuesto que ya mucha gente tuvo el mismo problema. Aquí les dejo los dos vínculos que encontré mejor, el primero el oficial y el segundo (extra-oficial) sencillo, pero con estados sólo de EEUU:


Están en inglés, pero a final de cuentas si queremos algo internacionalizable (el común hoy día), guste o no, esa es la segunda lengua por excelencia.

Barajitas premiadas (#9) - netcat

Supongamos que necesita una conexión telnet (sobre Windows) o rsh (sobre Linux) y no tiene estas herramientas a la mano o por alguna razón no desea utilizarlas (muchas razones me vienen a la mente, pero me las reservo porque este artículo tiene fines pedagógicos, o en todo caso de white hacking, y no vandálicos).

Pues, también puede utilizar necat para esto y listo; abordamos la herramienta en el artículo anterior.

La idea es dejar a netcat escuchando donde desea iniciar la consola remota y especificar que inicie un intérprete de comandos cuando alguien inicie una conexión por ese puerto.

En la máquina remota escucharía de la siguiente forma:
$ netcat -l -p 1234 -e /bin/bash

Y luego en la máquina local lo siguiente sería totalmente válido:
$ netcat localhost 1234
ls / #este comando se ejecutará remotamente (abajo se muestra la salida)
bin
boot
cdrom
dev
etc
home
initrd.img
lib
lost+found
media
mnt
opt
proc
root
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz

Ahora, en el momento en que cierre el cliente, el netcat que corre del lado del servidor se cerrará. Para evitar esto, podemos correrlo dentro de un ciclo infinito, algo como:
$ while true; do netcat -l -p 1234 -e /bin/bash; done

Ahhhhh y a este punto usted se preguntará, ¿y cómo hago para cifrar el canal? para ello OpenSSL vendría de perlas, esa la dejo para otro artículo!


La navaja suiza

Netcat es sin duda una herramienta indispensable para cualquier sysadmin. Los soldados del ejercito suizo no van a la guerra sin su navaja, por qué usted habría de olvidarla...

Es una herramienta que permite escribir y leer datos a través de la red - sobre el protocolo TCP/IP. Proximamente espero escribir algunos artículos con ejemplos varios al respecto.

Usted puede hacer que netcat escuche en un determinado puerto TCP utilizando la opción -l. Entonces, hay un ejemplillo -que siempre llevé conmigo a clase mientras estuve de profe- que permite estudiar: qué envían los navegadores a los servidores en la red cuando hacen peticiones HTTP; por supuesto que podría encender algún sniffer y verlo, pero con netcat me parece algo más pedagógico.

Primero que nada instale netcat con APT, YUM, o directamente con un RPM, DEB, compilándolo, en fín, como desee. Luego, puede establecer un chat punto a punto sencillo:

$ netcat -l -p 1234 #esto en una consola
$ necat localhost 1234 #esto en otra consola, luego escriba y ENTER (vea las salidas en cada una de las consolas)

Ahora a lo nuestro, lo que quería demostrar de las peticiones HTTP. La idea es dejar al necat escuchando en un puerto, configurar el navegador Web para que utilice como proxy nuestro socket de netcat y luego hacer una petición... Verá como se genera la salida; que puede almacenar en un archivo y luego utilizarla (esto lo explicaremos en otro artículo).

La configuración del proxy...



Netcat escuchando y su salida en pantalla luego de realizar -con el navegador- una petición a http://netcat.sourceforge.net/...
$ netcat -l -p 1234

GET http://www.google-analytics.com/__utm.gif?utmwv=1.3&utmn=968922939&utmcs=ISO-8859-1&utmsr=1280x800&utmsc=24-bit&utmul=es-ar&utmje=0&utmfl=10.0%20r22&utmdt=The%20GNU%20Netcat%20--%20Official%20homepage&utmhn=netcat.sourceforge.net&utmhid=1586803424&utmr=-&utmp=/&utmac=UA-398133-1&utmcc=__utma%3D100602113.1703963196.1279727538.1279727538.1279727538.1%3B%2B__utmz%3D100602113.1279727538.1.1.utmccn%3D(organic)%7Cutmcsr%3Dgoogle%7Cutmctr%3Dnetcat%7Cutmcmd%3Dorganic%3B%2B HTTP/1.1
Host: www.google-analytics.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.0.11) Gecko/2009061212 Iceweasel/3.0.6 (Debian-3.0.6-3)
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,es-ve;q=0.7,fr;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Proxy-Connection: keep-alive
Referer: http://netcat.sourceforge.net/

Fíjese en el detalle de la salida... La petición (el sitio utiliza Google Analitycs para llevar las estadísticas de uso; y quién no lo hace hoy día!!!) mis lenguages configurados, encoding, entre otros.




martes, 20 de julio de 2010

Barajitas premiadas (#8) - SSH port forwarding

La barajita de hoy tiene un valor sentimental importante para mi... jejejeje

Esta sí que la he utilizado bastante y no me canso de bendecirla. La explico con un ejemplo para que se entienda más fácil...

Imagine que está en un entorno de desarrollo donde usted tiene su máquina y accesso vía SSH al servidor de Calidad. Este servidor está protegido con un firewall y no puede acceder desde su máquina a otro puerto del mismo, que no sea el 22 (puerto SSH por omisión).

La cuestión surge cuando usted, que tiene acceso vía SSH, desea conectarse a la BD PostgreSQL que está corriendo en ese servidor desde su máquina, usted necesita acceder al puerto 5432 (puerto PostgreSQL por omisión) y sabe que cuando está conectado al servidor de forma local tiene acceso, pero de forma remota no. Entonces...

Usted puede crear un tunel (además sobre SSH - cifrado) y establecer una correlación entre un puerto local y el puerto remoto!! Creada la correlación, se conectaría a la BD como de forma local, pero realmente SSH estaría enviando toda la info al puerto en la máquina remota... qué fácil ah? Veamos cómo podría resolver el problema que he comentado.

$ ssh -NL 1234:localhost:5432 a@example.com & 
$ psql -h localhost -p 1234 mydb myuser

El primer comando, crea una conexión SSH entre los puertos local 1234 y remoto 5432 (opción -L) para el usuario a del servidor (example.com). Utilizo la opción -N para que no sea iniciada una consola remota y &.para que el proceso quede en background.

Luego, inicio una conexión con la BD como si fuese local para el usuario myuser y la BD mydb.


SOA y Symfony

Cuando hablamos de Arquitecturas Orientadas a Servicio (SOA - por sus siglas en inglés) es común pensar en Servicios Web y todo lo que conllevan. Mucha gente comienza metiendo Servicios Web por todos lados...

Yo prefiero pensar en arquitecturas donde la lógica de negocio se encuentra perfectamente desacoplada y que luego puede ser aprovechada parte de ésta a través de, por ejemplo SOAP, valiéndose de una fachada.

Para la gente que programa en Java es común pensar en algo como: peticiones HTTP que toma algún framework MVC (Ej. Struts), que delega en Servicios que llaman DAOs, que a su vez se apoyan en un ORM (Ej. Hibernate)... Algo por el estilo, y bueno por supuesto inversión de control (IoC - por sus siglas en inglés) de Spring.

Luego, Symfony ofrece un manejo excepcional MVC, pero... Mucha gente, sobre todo al utilizar formularios olvida la capa de servicios y adiós SOA. A continuación les presento un ejemplo sencillo al respecto:

Primero: Creando la clase de servicio

De momento defineremos una clase Usuario de servicio con un método eliminar (simulado):

//file: /lib/service/user.class.php

class UserService {
 //...
 
 public static function remove($id) {
  //TODO elimina un usuario de BD según el id dado y en caso de error arroja una excepción
 }
 //...
}

Fíjese que el archivo fue colocado dentro de la carpeta lib del proyecto, por ello, Symfony la cargará automáticamente por usted. Además, el método remove es estático porque éste no requiere del estado de un "posible" objeto; generalmente los métodos de servicio son estáticos, puesto que la lógica desarrollada en ellos no requiere estado.

Segundo: El controlador

El código del controlador o lógica de presentación (como prefiero llamarla) deberá colocarlo dentro de su acción, por ejemplo:

//file: /apps/myapp/modules/user/actions/actions.class.php

class userActions extends sfActions
{
 //...

 public function executeRemove(sfWebRequest $request)
 {
  $id = $request->getParameter('id');

  //TODO aquí deberá realizar todas las validaciones pertinentes

  try {
   UserService::remove($id);

   //Manejar el caso de éxito
  } catch (MyCustomException $mce) {
   //TODO manejar la excepción
  }

  //...
 }

 //...

Fíjese que para invocar el método remove de la clase UserService no necesité hacer ningún include o algo parecido. El día de mañana si necesito exponer este método como servicio, simplemente haría una fachada, por ejemplo:

Tercero: La fachada

//file: /lib/soap/user.class.php

class UserSOAP
{
 //...

 public function remove($id)
 {
  //TODO aquí deberá realizar todas las validaciones pertinentes

  try {
   UserService::remove($id);

   //Manejar el caso de éxito
  } catch (MyCustomException $mce) {
   //TODO manejar la excepción
  }

  //...
 }

 //...

Por supuesto que debería utilizar el paquete SOAP de PEAR o algún plugin de Symfony (Ej. ckWebServicePlugin) para que efectivamente esta fachada sea invocada al llamar un Servicio Web.

IMPORTANTE: Sobre todo debe notar que en el execute de mi acción no hay, ni debería haber, ninguna sentencia SQL. Ni siquiera del tipo findBy (métodos de la clase par)... Todas las llamadas a BD deberían estar dentro de servicios, porque sino estaría acoplando la lógica de presentación (execute del action) con la lógica de negocio (service) Y ESO NO SE HACE!:D


jueves, 15 de julio de 2010

Barajitas premiadas (#7) - eclipse.ini

Esta es una barajijta sencillita pero de gran utilidad! Cuando nuestro Eclipse se queda corto de memoria y queremos que tome más, pues simplemente debemos decirlo a la Java VM.

Para nuestra fortuna, Eclipse tiene un archivo donde podemos configurar diversos parámetros que éste considerará al iniciar, eclipse.ini ubicado en la raíz de la instalación, allí podemos indicar a la Java VM que tome más memoria heap o stack con las opciones -Xmx o -Xss respectivamente.

Generalmente es suficiente aumentar sólo el espacio heap, por ejemplo: -Xmx512M o -Xmx1G.

Espero escribir más adelante acerca del heap y el stack, de momento les dejo un interesante artículo como referencia.

Creando un proyecto en Symfony con PortgreSQL desde cero

A continuación les dejo una guía rápida para crear un proyecto en Symfony con una base de datos PostgreSQL desde cero, asumiendo que ya tenemos un script DDL y no haremos ningún módulo de momento.

Creando la BD...
$ sudo su - postgres #estoy iniciando sesión como postgres en el sistema
$ createuser myuser -P #puede hacerlo admin si lo desea, con contraseña mypassword
$ createdb mydb -O myuser #creando la BD con myuser como dueño
$ exit
$ psql mydb myuser -h localhost < scriptDDL.sql #creando los objetos en la BD
Creando el proyecto...
$ mkdir /var/www/myproj #creando el proyecto en el DocumentRoot de Apache
$ cd /var/www/myproj/
$ symfony generate:project myproj #inicializando proyecto
$ ln -s $RUTA_SYMFONY/data/web/sf web/ #copiando enlaces básicos de symfony
$ symfony generate:app myapp #inicializando aplicación
$ symfony configure:database "pgsql:host=localhost;dbname=mydb" myuser mypassword #configurando BD
$ symfony generate:build-schema #construyendo schema de la BD (config/doctrine/schema.yml)
$ symfony doctrine:build-model #construyendo modelo a partir del schema
$ symfony doctrine:build-forms #construyendo forms a partir del modelo
$ symfony doctrine:build-filters #construyendo filtros a partir del modelo
Podría ver un adelanto del proyecto, hasta ahora -sin módulos- en: http://localhost/myproj/web/myapp_dev.php

miércoles, 14 de julio de 2010

Barajitas premiadas (#6) - rsync

Esta barajita es especialmente útil! El comando rsync... Les comento el problema que me planteó utilizarlo, para ejemplificar mejor. Ni les comento de replicas para respaldos o hasta bases de datos en línea, lo máximo!

Yo tengo una cuenta en un servidor en la Web y tengo acceso SSH al mismo. La cuestión es que debo subir mis códigos al servidor, porque las pruebas que estoy haciendo deben correr allí.

Ahora, cada vez que necesitaba copiar mis archivos, debía hacerlo vía SCP o FTP (que no me gusta por temas de seguridad) y esto demoraba mucho, porque siempre debían copiarse todos los archivos. El ideal, sería copiar sólo los archivos que cambiaron para disminuir mis tiempos de despliegue. Allí es cuando entra rsync en acción. Simplemente especifico que deseo utilizar SSH, cuáles directorios copiar, cuáles excluir y a dónde enviarlos. A continuación un pequeño script, que luego retomaré porque le hice modificaciones, que espero les sea de utilidad:

#!/bin/bash

USER='a'
SERVER='example.com'
OPTS='--exclude=cache --exclude=log'
SOURCE_DIR='.'
REMOTE_DIR='~/www/myapp'

# Synchronizing files
rsync -r -e ssh $OPTS $SOURCE_DIR $USER@$SERVER:$REMOTE_DIR

martes, 13 de julio de 2010

Barajitas premiadas (#5) - Syntax Highlighter

Como podrá darse cuenta mis nuevos artículos incluyen un resaltador de sintaxis (syntax highlighter).

Los resaltadores de sintaxis mejoran la presentación de nuestros artículos. No los había utilizado hasta el momento porque no conseguía uno que realmente me gustara, hasta que por fin... El que he escogido, SyntaxHighlighter, es bastante bueno y reconoce un montón de lenguajes... Se los recomiendo!

Barajitas premiadas (#4) - Debian Backports

Barajitas premiadas (#4) - Debian Backports

Al utilizar alguna versión de Debian es común mantener paquetes y repositorios estables. Debian trabaja con diferentes repositorios, según versión, con diferentes niveles de madurez: unstable, testing, stable u oldstable.

El problema surge cuando desea utilizar paquetes más actualizados y entonces comienza a mezclar entornos estables (stable) con pruebas (testing), o hasta en casos extremos, inestables (unstable). Para estos casos, siempre que sea posible, se recomienda utilizar los repos backport.

La idea es agregar el repo a su archivo de fuentes APT y luego especificarlo cuando desee utilizarlo; esto es excelente, APT no lo considerará al buscar paquetes al menos de que usted lo indique.

Esto me fue de especial ayuda al instalar mi nueva impresora HP (Deskjet F2420). Pues resulta que el paquete hpijs-ppd estable de mi Debian Lenny no contenia el driver porque era muy reciente, entonces, configure el repo backport para Lenny y listo!!! A continuación los pasos que seguí:

# echo 'deb http://www.backports.org/debian lenny-backports main contrib non-free' >> /etc/apt/sources.list
# apt-get update
# aptitude -t lenny-backports install hpijs-ppds


Cómo incluir archivos JS dentro de otros

Cuando trabajamos con JavaScript es buena práctica colocar nuestro código dentro de archivos JS, en aras de hacer nuestro código más fácil de mantener. Luego, una vez me surgió la siguiente pregunta: considerando que tenía un JS y que quería utilizar funciones y/u objetos definidos en otro JS ¿cómo podía incluir uno en otro? Algo como los include de C o PHP.

La respuesta es: no es necesario! Todos los JS que se cargan en una página son montados en la RAM de la máquina por lo que no es necesario incluir archivos JS dentro de otros. Según lo comentado, tomando el código de nuestro artículo anterior, el ejemplo mostrado a continuación es completamente válido:

//archivo: usuario.class.js
const ROL_INVITADO = 'invitado';
const ROL_ADMIN = 'admin';

function Usuario(nombre, clave, rol) {
 var nombre = nombre;
 var clave = clave;
 var rol = rol;

 //setters
 this.setNombre = function(_nombre) { nombre = _nombre; };
 this.setClave = function(_clave) { clave = _clave; };
 this.setRol = function(_rol) { rol = _rol; };

 //getters
 this.getNombre = function() { return nombre; };
 this.getClave = function() { return clave; };
 this.getRol = function() { return rol; };

 //funciones
 this.toString = function() {
  retorno = 'nombre: ' + this.getNombre() + ', ';
  retorno += 'clave: ' + this.getClave() + ', ';
  retorno += 'rol: ' + this.getRol();
   
  return retorno;

 };
}

//archivo: cargar_usuarios.js
var usuario1 = new Usuario('rodolfo', '123456', ROL_ADMIN);
var usuario2 = new Usuario('pepe', '654321', ROL_INVITADO);

<html>
 <head>
  <title>Ejemplo clases JavaScript</title>
  <script type="text/javascript" src="usuario.class.js"></script>
  <script type="text/javascript" src="cargar_usuarios.js"></script>
 </head>
 <body>
  <script language="javascript">
   document.writeln(usuario1);
   document.writeln('<br/>');
   document.writeln(usuario2);
  </script>
 </body>

</html>

Fíjese como dentro del archivo cargar_usuarios.js no incluí el usuario.class.js. Además, dentro del html utilizo las variables declaradas en el cargar_usuarios.js sin ningún problema. Recuerde, todo queda en la RAM!


lunes, 12 de julio de 2010

Cómo trabajar OO en JavaScript

A continuación un ejemplo que permite ver cómo trabajar con "clases" en JavaScript (JS). Podrá observar que el constructor de la "clase", y lo coloco entre comillas porque más bien parece una estructura de datos potenciada, está definido por la firma de la función. Los atributos o funciones definidos con las palabras reservadas this o var son de acceso público o privado respectivamente. NOTA: Los parámetros de las funciones setters llevan el guión bajo "_", porque no podría utilizarse la variable this ya que tendrían que haberse declarado los atributos como públicos (utilizando this) y no privados (utilizando var).

Ahora el código:

<html>
<head>
<title>Ejemplo clases JavaScript</title>
<script language="javascript">
const ROL_INVITADO = 'invitado';
const ROL_ADMIN = 'admin';

function Usuario(nombre, clave, rol) {
var nombre = nombre;
var clave = clave;
var rol = rol;

//setters
this.setNombre = function(_nombre) { nombre = _nombre; };
this.setClave = function(_clave) { clave = _clave; };
this.setRol = function(_rol) { rol = _rol; };

//getters
this.getNombre = function() { return nombre; };
this.getClave = function() { return clave; };
this.getRol = function() { return rol; };

//funciones
this.toString = function() {
retorno = 'nombre: ' + this.getNombre() + ', ';
retorno += 'clave: ' + this.getClave() + ', ';
retorno += 'rol: ' + this.getRol();

return retorno;

};

}
</script>
</head>
<body>
<script language="javascript">
var usuario = new Usuario('rodolfo', '123456', ROL_ADMIN);
document.writeln(usuario);
document.writeln('<br/>');

usuario.setRol(ROL_INVITADO);
document.writeln(usuario);
</script>
</body>
</html>

domingo, 11 de julio de 2010

Barajitas premiadas (#3) - /dev/null

Esta es una barajita que voy a escribir antes de que se me olvide...

Puede parecer trivial, perooooo... El archivo null dentro de la carpeta /dev, el /dev/null, es una especie de hoyo negro de los sistemas *nix.

Por ejemplo, si queremos vaciar un archivo rápidamente...


$ cat /dev/null > NOMBRE_ARCHIVO


O, por ejemplo, si tenemos un comando que arrojará errores y no deseo hacer nada con ellos, ni siquiera echarlos a un archivo, siempre puedo enviarlos al "hoyo negro":


$ find / -name \*.conf 2> /dev/null


El comando de arriba buscará dentro de todo el sistema (desde la raíz "/") archivos que terminen con la extensión .conf. Esto retornará errores por permisos insuficientes para buscar en varios directorios (fíjese que el comando es ejecutado como un usuario ordinario del sistema, por el símbolo de "$" antes del comando y no de "#" que identifica al usuario root). Entonces estos errores (2>) son redireccionados al "hoyo negro".

Esto también es súper útil cuando configuro tareas (Ej. CRON), porque si ocurren errores, serán enviados a la bandeja de entrada de correos locales del usuario dueño de la tarea y podríamos ocupar espacio en disco innecesario. OJO, esto depende del caso y no siempre se recomienda obviar los mensajes de error.

Barajitas premiadas (#2) - man

La barajita del día... El comando man de *nix nos permite observar el manual correspondiente para una entrada (generalmente un comando). Me puedo mover con las flechas (arriba y abajo), pg down (barra espaciadora), pg up (b) o inclusive buscar patrones (presionando barra "/", colocando el patrón y ENTER). Para salir q.

Ahora, hay veces en las que tengo más de un manual para la misma entrada o simplemente deseo conocer si existe manual para algo. Para ello, puedo utilizar la opción -k del comando. A continuación presento un ejemplo que permite obtener las coincidencias para manuales de printf, obteniendo dos respuestas concretas y luego abriendo una de ellas específicamente. Fíjese que filtro la salida con el comando grep para especificar sólo las líneas que contengan la palabra print al inicio; para comprobar el comportamiento, puede probar quitando el pipe (|) y luego colocándolo de nuevo


rodolfo@rcampos-laptop:~$ man -k printf\* | grep ^print
printf (3) - conversión de salida formateada
print (1) - execute programs via entries in the mailcap file
print_description (3snmp) - mib_api functions
print_mib (3snmp) - mib_api functions
print_objid (3snmp) - mib_api functions
print_value (3snmp) - mib_api functions
print_variable (3snmp) - mib_api functions
printafm (1) - Print the metrics from a Postscript font in AFM format...
printenv (1) - print all or part of environment
printers.conf (5) - printer configuration file for cups
printf (1) - format and print data
rodolfo@rcampos-laptop:~$ man 3 printf

Cómo configurar un Trust Store en Java para conexiones sobre SSL

A continuación se presentan un conjunto de pasos que puede seguir para configurar un almacén de claves (keystore) como de "confianza" para una máquina virtual de Java. Esto resulta indispensable cuando deseamos que nuestra aplicación se conecte con servicios sobre SSL, por ejemplo: Servicios Web (sobre SSL - HTTPS), Servidores FTP (sobre SSL - FTPS) o Servidores SMTP (sobre SSL - SMTPS).

La Java VM no le permitirá conectarse con estos servicios sobre SSL a menos de que hayan sido configurados como confiables, para lo que deberá configurar el almacén de confianza (Trust Store).

  1. Obtener el certificado, para lo cual podrá correr el shell script retrieve_certificate.sh (mostrado al final de este artículo)
    $ ./retrieve_certificate.sh IP PUERTO > NOMBRE_CERT
  2. Crear el almacén de claves (keystore)
    $ keytool -import -keystore NOMBRE_KEYSTORE -file NOMBRE_CERT -alias NOMBRE_REF_CERT
  3. Chequear keystore
    $ keytool -list -keystore NOMBRE_KEYSTORE
  4. Agregar parámetros del keystore al Java VM. Por ejemplo, en tomcat:
    JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=NOMBRE_KEYSTORE -Djavax.net.ssl.trustStorePassword=CLAVE_KEYSTORE

A continuación el shell script retrieve_certificate.sh (extraído de aquí):

#!/bin/sh
#
# usage: retrieve-cert.sh remote.host.name [port]
#
REMHOST=$1
REMPORT=${2:-443}

echo |\
openssl s_client -connect ${REMHOST}:${REMPORT} 2>&1 |\
#openssl x509 -connect ${REMHOST}:${REMPORT} 2>&1 |\
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

Cómo realizar queries con HQL (una sugerencia para evitar SQL injection)

Cuando trabajamos con Hibernate y deseamos realizar queries con el lenguaje de consultas propio, HQL, recomiendo trabajar con parámetros a la forma de sentencias preparadas (prepared statements). Por ejemplo:


@Override
public Usuario login(Cuenta cuenta) {

Query query = this.getEntityManager().createQuery("from Usuario where cuenta.login = :login and cuenta.password = :password ");

query.setParameter("login", cuenta.getLogin());
query.setParameter("password", cuenta.getPassword());


List result = query.getResultList();

if (result.size()==0){
return null;
}
return result.get(0);

}


En el código mostrado arriba se puede ver como los parámetros "login" y "password" son pasados en diferido y no concatenados directamente en el string, esto puede salvarle la vida contra ataques de SQL injection. No estoy seguro de que además obtenga ganancias en tiempo de ejecución, para llamadas posteriores, porque estas sentencias sean preparadas y almacenadas en el catálogo del RDBMS.

sábado, 10 de julio de 2010

Barajitas premiadas (#1) - find

Este es el primero de un seriado de artículos que estaré publicando con herramientas que siempre debemos tener a la mano. Esas herramientas que siempre nos pueden salvar la vida, barajitas! (figuras, de esas que se pegan en un álbum). Y como éstas son especialmente útiles, las he bautizado como barajitas premiadas.

La primera barajita, el siempre bien ponderado y siempre entrañable en otros sistemas no *nix, el find.

El comando find, en su forma más básica, permite buscar archivos que cumplan con algún patrón, por ejemplo, para buscar todos los archivos con extensión .php dentro del directorio /var/www (generalmente, DocumentRoot del Apache):


$ find /var/www -name \*.php


Ahora, la utilidad específica que les quiero presentar es la siguiente:


$ find DIRECTORIO_DESEADO -name ALGÚN_PATRÓN -exec COMANDO '{}' ';'


Este comando buscará dentro de un DIRECTORIO_DESEADO todos los archivos que cumplan con ALGÚN_PATRÓN y para cada uno de ellos aplicará el COMANDO deseado. Note que la cadena '{}' será reemplazada por el nombre de cada archivo que cumpla con el patrón y la cadena ';' indica el fin del comando. Veamos un ejemplo concreto y muy, muy útil:


rodolfo@rcampos-laptop:/opt/symfony-1.4.6$ find . -name \*.php -exec grep 'function form_tag(' '{}' ';'
function form_tag($url_for_options = '', $options = array())
rodolfo@rcampos-laptop:/opt/symfony-1.4.6$ find . -name \*.php -exec grep -l 'function form_tag(' '{}' ';'
./lib/helper/UrlHelper.php
rodolfo@rcampos-laptop:/opt/symfony-1.4.6$


El ejemplo de arriba muestra cómo puedo buscar dentro del directorio raíz de Symfony dónde puede estar declarada la función form_tag y luego en la siguiente línea, con la opción -l del comando grep, pido el nombre del archivo donde se haya encontrado la coincidencia. Después de esto, sólo queda abrir el archivo y ver el detalle de la función. No hace falta ni ahondar en lo poderoso y útil que puede ser esto, sobre todo al trabajar con frameworks de código abierto como Symfony. Recuerde que el comando grep busca coincidencias, según un patrón, dentro de un archivo.

Otra súper útil, cuando trabajo con Subversion (SVN) y deseo mover la carpeta de un proyecto sincronizado... Si no quiero que esta carpeta lleve consigo todos los archivos de SVN, debería borrar las carpetas .svn dentro de cada directorio. Además, esto hace que el proyecto pese mucho más de lo que debería. La barajita:


rodolfo@rcampos-laptop:/var/www/myproj$ find . -name .svn -exec rm -rf '{}' ';'

viernes, 9 de julio de 2010

Palabras necias

El blog de mi pana Edwin... http://edwinvaldez.com/

Cómo reasignar (resetear) la clave de un usuario en linux (una de tantas formas)

Esto es muy útil para admins! Este método es generalmente utilizado cuando se olvida (o alquien nos ha cambiado) una contraseña. Ahora, si realmente deseamos proteger nuestro sistema contra alquien que pueda cambiar una contraseña, teniendo acceso remoto o local al mismo, mejor investigar también otros métodos, algunos de ellos: stack overflows, exploits y symbolic links escalation.

Dicho esto, sigamos adelante, primero debe tener acceso físico a la máquina y poderla reiniciar... Si es así...

Reinicie la máquina, cuando consiga el gestor de arranque (probablemente GRUB), presione la letra e (edit), generalmente sobre la primera línea - correspondiente al kernel más actualizado.

Una vez ubicado en el modo de edición, debe colocarse sobre la línea que se refiere a la carga del kernel, debería ser la primera línea de unas 2 o 3 opciones, y cuando esté allí presione c (de command) o e (de edit) dependiendo del gestor, al presionar esto, debería ver una consola con la línea que escogió.

Al final de la linea antes de la opción ro, si es que la tiene, agregue init=/bin/sh

Luego presione enter y posicionándose nuevamente sobre la línea, presione la b (de boot) para que la máquina arranque con esa opción... Al arrancar debería caer en una consola; apenas terminado el reconocimiento de dispositivos.

Estando en la consola deberá remontar el disco duro con la opción de escritura para poder cambiar o borrar la clave del root o cualquier otro usuario, para ello deberá escribir:


# mount / -o remount, rw


Listo! Ahora sólo deberá ingresar una nueva contraseña para el usuario que desee:


# passwd CUALQUIER_USUARIO


Otra opción, en lugar de utilizar el comando passwd, es ingresar al archivo /etc/shadow y borrar el cifrado de la contraseña para un usuario, es decir, el montón de caracteres después de los dos puntos (:) seguidos al nombre del usuario, hasta los próximos dos puntos (:). El usuario quedaría sin contraseña.

Luego de hacer esto salve, reinicie y listo!

NOTA: Ubuntu instala un modo de mantenimiento que le permitirá hacer esto simplemente seleccionando la opción del gestor de arranque... Sin todo lo de init=/bin/sh y remontar el disco. Y bueno, esto siempre puede evitarse colocando contraseñas al gestor de arranque, para lo que alquien podría entrar con un live CD (montar la unidad y acceder al /etc/shadow), lo que también puede evitarse colocando inicio por disco y definiendo contraseña al BIOS, para lo que también alquien podría brincar el BIOS quitando la pila al computador (OJO. Hay programas capaces de hacer esto)... En fin, si desea evitar que alquien pueda cambiar su contraseña de esta forma, siempre puede encerrar el equipo bajo llave ;D

jueves, 8 de julio de 2010

Shell script de respaldos

Este script genera respaldos de repositorios SVN, trac y BDs PostgreSQL y las envia a un almacén secundario vía SSH. Podría utilizarse para generar respaldos en un servidor local y enviarlos a otro en la red. Se asume que para las conexiones SSH (utilizando SCP) existe relación de confianza entre los servidores (ver artículo anterior por cualquier duda).


#!/bin/sh
FECHA=`date +%d%m%y`_`date +%s`
DIRECTORIO="/respaldos"
USUARIO="a"
SERVIDOR="192.168.1.104"
USUARIO_BD="admin"

###### RESPALDO SVN ######

#Creando respaldo (comprimido) en formato dump del repo (Almacén Local)
svnadmin dump /repositorio/ | gzip > $DIRECTORIO/repo/repositorio_$FECHA.dmp.gz

#Copiando al Almacén de Respaldos
scp $DIRECTORIO/repo/repositorio_$FECHA.dmp.gz $USUARIO@$SERVIDOR:~/backup_servidor/repo/repositorio_$FECHA.dmp.gz

###### RESPALDO TRAC ######

#Creando respaldo del trac
trac-admin /trac hotcopy $DIRECTORIO/trac/trac
tar cfz $DIRECTORIO/trac/trac_$FECHA.tar.gz $DIRECTORIO/trac/trac
rm -r $DIRECTORIO/trac/trac

#Copiando al Almacén de Respaldos
scp $DIRECTORIO/trac/trac_$FECHA.tar.gz $USUARIO@$SERVIDOR:~/backup_servidor/trac/trac_$FECHA.tar.gz

###### RESPALDO BD ######

#Creando respaldo de la BD "bd_a"
pg_dump -U $USUARIO_BD bd_a | gzip > $DIRECTORIO/bd/bd_a_$FECHA.sql.gz

#Creando respaldo de la BD "bd_b"
pg_dump -U $USUARIO_BD bd_b | gzip > $DIRECTORIO/bd/bd_b_$FECHA.sql.gz

#Llevando respaldo al servidor Web de Softclear
scp $DIRECTORIO/bd/*_$FECHA.sql.gz $USUARIO@$SERVIDOR:~/backup_servidor/bd/

Cómo configurar SSH para realizar conexiones sin contraseña

Ahora sí, al grano...

Utilizar SSH para conectarse a máquinas de forma remota es muy común. Luego, hay momentos en los que desearíamos obviar el ingreso de contraseña, bien sea porque no deseamos divulgarla o simplemente porque nos fastidia tener que colocarla constantemente.

Para que una máquina pueda conectarse a otra vía SSH, sin la necesidad de colocar una contraseña, se asume que ambas mantienen una relación de confianza, en este caso unidireccional, es decir, que "A" confíe en "B", no implica necesariamente que "B" confíe en "A".

Ya en el artículo anterior, Cómo funciona SSH, explicamos algo de SSH, podría considerar este artículo como su continuación...

Supongamos que "A" desea conectarse a "B" vía SSH sin necesidad de ingresar su contraseña, o, y realmente prefiero esta explicación, "B" considera que "A" mantiene una relación de confianza con él, por lo que le permitirá iniciar una sesión para un usuario específico sin la necesidad de autenticarse explicitamente.

Lo que debe hacer "A" es generar un par de claves (pública y privada) y enviarle su clave pública a "B", para que esta la almacene en su base de datos de máquinas confiables. Luego, cuando "A" inicie sesión -para el usuario que hayan acordado- "B" le concederá el permiso sin la petición explícita de una contraseña.

Pongámonos técnicos...

Para generar la clave:


rodolfo@rcampos-laptop:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/rodolfo/.ssh/id_rsa): ENTER
Enter passphrase (empty for no passphrase): ENTER
Enter same passphrase again: ENTER
Your identification has been saved in /home/rodolfo/.ssh/id_rsa.
Your public key has been saved in /home/rodolfo/.ssh/id_rsa.pub.
The key fingerprint is:
9d:0f:4e:8c:b5:bb:f4:c3:ec:e3:79:8b:59:0b:1a:d1 rodolfo@rcampos-laptop
The key's randomart image is:
+--[ RSA 2048]----+
| |
| |
| . |
| = + |
| S O E |
| o = |
| =oo . |
| . ==*.. |
| ooB+o. |
+-----------------+
rodolfo@rcampos-laptop:~$


Ahora tenemos la clave pública en la carpeta .ssh ubicada en nuestro $HOME (/home/rodolfo/.ssh/id_rsa.pub), sólo nos resta enviarla al host remoto y que en este se agregue al archivo authorized_keys dentro del directorio .ssh ubicado en el $HOME del usuario seleccionado. Por ejemplo:


rodolfo@rcampos-laptop:~$ scp /home/rodolfo/.ssh/id_rsa.pub a@myhost.com:~/.ssh
a@myhost.com's password:
id_rsa.pub 100% 404 0.4KB/s 00:00
rodolfo@rcampos-laptop:~$ ssh a@myhost.com "cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys"
a@myhost.com's password:
rodolfo@rcampos-laptop:~$ ssh a@myhost.com
Last login: Mon Jul 5 06:45:40 2010
a@myhost.com [~]#

Cómo funciona SSH

Realmente quería hablar de conexiones sobre SSH confiables o sin contraseñas, pero primero debemos entender SSH, hagámoslo con un ejemplo:

"A" necesita comunicarse con "B", pero no podría hacerlo directamente porque otro nodo, como "C", podría interceptar la comunicación y enterarse de cosas que no debería. Por ello, "A" y "B" deben comunicarse bajo un canal seguro. Este canal seguro es establecido bajo un canal cifrado haciendo uso de una clave "que sólo ellos dos conocen"; específicamente son utilizados algoritmos de cifrado simétrico para realizar esto.

Ahora, el único problema a este punto es la clave que "A" y "B" deberían compartir (secreto compartido). Para enterarse cada uno de ésta, antes la misma debe ser generada (por uno de ellos) y compartida (enviada al otro).

La clave (a compartir) es enviada al otro bajo un canal seguro empleando algoritmos de cifrado asimétrico; por supuesto, también la clave es compartida sobre un canal seguro!!

La comunicación sobre canales cifrados con algoritmos asimétricos necesita de dos claves por cada nodo. Es decir, "A" y "B" tendrían dos claves cada uno.

La idea es que cada uno de los nodos tenga una clave privada (que sólo él y más nadie conoce) y una pública (que como el nombre lo dice, todos conocen o al menos podrían). Luego, cuando los mensajes son cifrados con la clave privada, sólo pueden descifrarse con la pública (o viceversa).

Ahora, por fin al grano, "A" desea comunicarse con "B", entonces: "A" genera una clave, la cifra con la clave pública de "B" y envía el resultado (mensaje) a "B". Luego, "B" descifra el mensaje (la clave compartida) con su clave privada y voalá!, a este punto "A" y "B" tienen un secreto compartido. De aquí en adelante, toda la comunicación es cifrada con un algoritmo simétrico.

Podrían preguntarse ¿para qué todo este problemón?, ¿por qué no realizar toda la comunicación sobre canales cifrados con algoritmos asimétricos? La respuesta es que se podría, pero sería demasiado lento!! Por ello, generalmente los algoritmos de cifrado asimétrico son utilizados únicamente para compartir claves que después servirán para cifrar canales con algoritmos simétricos.

Increible todo el tema de cifrado, eh? Bruce Schneier en su Applied Cryptography, literatura obligada para cualquier profesional del área de seguridad, escribió: "The lesson here is that it is insufficient to protect ourselves with laws; we need to protect ourselves with mathematics..."

miércoles, 7 de julio de 2010

Cómo utilizar Git sobre Hostmonster o Bluehost

Git es un Sistema para Controlar Versiones (SCV) inventado por Linus Torvalds. Fue diseñado considerando el proceso de desarrollo de Linux y hoy día es uno de los SCV más utilizados.

Lo que hace a Git tan atractivo es la capacidad de manejar versiones de forma distribuida bajo un enfoque KISS (Keep it simple, stupid!). Por ejemplo, Git es perfecto para un esquema típico de desarrollo de software libre, donde se crean unidades de desarrollo con líderes que deben velar porque todo lo desarrollado por sus supervisados esté de la mejor forma posible. Luego, estos líderes son los encargados de subir sus códigos a repositorios de datos con mayor visibilidad, para que sus líderes validen el trabajo y así sucesivamente.

Además de lo mencionado anteriormente, Git brinda un manejo excepcional de branches y tags!!

El objetivo de este artículo es explicar cómo pude trabajar con un repositorio Git en Hostmonster (hostmonster.com).

Primero: Instalando Git

Debe instalar Git en su máquina para poderlo utilizar, hacerlo, es muy sencillo:

# aptitude install git-core

Luego, lo que puede resultar un tanto problemático es instalar Git en Hostmonster donde por supuesto no tenemos permiso para instalar paquetes. Entonces la idea es descargar los fuentes de la aplicación, compilarlos e incluir la ruta bin del compilado en la variable de entorno PATH. En el siguiente enlace puede conseguir las instrucciones detalladas de cómo hacer esto. Lo único que cambié, fue el paquete Git, descargué la última versión estable (para la fecha de escritura de este artículo 1.7.0).

Segundo: Configurando el repositorio

Debe conectarse a su servidor de Hostmonster (para lo cual debe tener acceso SSH), crear la carpeta donde almacenará la información e iniciar el repo Git crudo (desnudo - bare). Para efectos de este ejemplo llamaré a mi sitio git-example.com.


$ ssh git@git-example.com
$ mkdir -p repo/myproj.git
$ cd repo/myproj.git
$ git --bare init


Luego, en su máquina deberá crear la carpeta donde ubicará los fuentes del proyecto, iniciar el repo Git, agregar al menos un archivo (para generar el branch master), configurar las variables uploadpack y receivepack (que el Git remoto utilizará para hacer push y pull), configurar el origen remoto para su repo y realizar el primer push.

Si a este punto tiene alguna duda acerca del funcionamiento de Git, de las operaciones push y pull le aconsejo leer del siguiente enlace.


$ mkdir -p projects/myproj
$ cd projects/myproj
$ git init
$ echo "README" > README
$ git add README
$ git commit -a -m "Initial commit"
$ git config remote.origin.uploadpack '$RUTA_REMOTA_ABSOLUTA_GIT/bin/git-upload-pack'
$ git config remote.origin.receivepack '$RUTA_REMOTA_ABSOLUTA_GIT/bin/git-receive-pack'
$ git remote add origin ssh://git@git-example.com/home/git/repo/myproj.git
$ git push origin master


De aquí en adelante trabaje tranquilamente y cada vez que desee hacer un commit repita los pasos:


$ git add *
$ git commit -a -m "Commit description"
$ git push


El resto de los usuarios podrá clonar el repo de la siguiente forma:


$ git clone -u '$RUTA_REMOTA_ABSOLUTA_GIT/bin/git-upload-pack' ssh://git@git-example.com/home/git/repo/myproj.git

martes, 6 de julio de 2010

Cómo interconectar PostgreSQL con Oracle

Este artículo explica cómo obtener datos almacenados en una BD Oracle desde PostgreSQL (a través de una vista). Esto permite obtener datos en línea y sin la necesidad de replicar la información en diferentes BDs.

La idea es crear una vista, que invocará un procedimiento almacenado, que se conectará a la BD Oracle y extraerá los datos.

El procedimiento almacenado fue programado en Java y registrado en PostgreSQL utilizando la librería Pl/Java.

Notas:

Este ejemplo fue montado sobre una máquina con Linux Debian Lenny. Para la versión actual de Pl/Java se tuvo que descargar el jdk 1.4 más reciente (aún y cuando ya fue declarado como obsoleto) debido a que la librería fue desarrollada con esta versión.

Es importante destacar que el procedimiento almacenado desarrollado fue compilado con la versión 1.4 del jdk.

Primero: Instalación de Pl/Java

Lo primero que debemos hacer es generar los archivos pljava.so y pljava.jar para que utilicen la versión de Sun del jdk y no la libre GCJ (esto en caso de que no se desee utilizar esta versión).

En el siguiente vínculo puede conseguir una guía que explica bastante bien cómo generar estos archivos (pljava.so y pljava.jar). Luego, puede descargarlos directamente de aquí. Recuerde que estos archivos fueron generados con la versión 1.4 del jdk de Sun.

En caso de que decida generar estos archivos usted mismo, es importante destacar que necesitará instalar los paquetes: libpq-dev y postgresql-server-dev-8.3.

Una vez descargados (o generados) los archivos, deberá copiarlos a la ruta donde PostgreSQL busca las librerías, por ejemplo: /usr/lib/postgresql/8.3/lib/

Ahora deberá definir las siguientes variables de entorno dentro del archivo environment de PostgreSQL (Ej. /etc/postgresql/8.3/main/environment):


JAVA_HOME = '/opt/j2sdk1.4.2_19'
LD_LIBRARY_PATH = '/opt/j2sdk1.4.2_19/jre/lib/i386:/opt/j2sdk1.4.2_19/jre/lib/i386/client'


Ambas variables de entorno permitirán a PostgreSQL localizar el jdk de Java y los archivos de librerías del sistema de Java (.so o .dll según el SO).

Una vez configurada la librería pljava y definidas las variables de entorno, se deberá correr el script install.sql incluido con la librería, para definitivamente culminar la instalación. El script podrá correrlo sobre la BD template1, para que todas las BD puedan utilizar la librería; sobre un template que usted defina, para habilitar determinadas BD; o directamente sobre la BD de su proyecto, para habilitarla sólo a ella.

Segundo: Programación del Procedimiento

En el siguiente vínculo puede descargar los fuentes de la aplicación. Podrá observar que los fuentes son acompañados de un jar que los contiene, esto debido a que los mismos deben ser empaquetados en un JAR para registrarlos posteriormente en PostgreSQL.

Importante: Deberá colocar el driver JDBC de Oracle acorde a la versión del jdk, en este caso 1.4 (ojdbc14.jar), dentro de la carpeta $JAVA_HOME/jre/lib/ext.

Tercero: Registrando el procedimiento almacenado

Luego deberá conectarse a la BD, registrar el JAR que contiene los procedimientos almacenados, definir un nuevo schema, definir un nuevo classpath, definir el procedimiento almacenado y definir la vista correspondiente. Por ejemplo:


SELECT sqlj.install_jar('file:///home/rodolfo/sigcne/sigcne.jar', 'sigcne', false);
CREATE SCHEMA oracle;
SELECT sqlj.set_classpath('oracle', 'sigcne');
CREATE FUNCTION oracle.getData() RETURNS SETOF varchar AS 'oracle.OrclConnection.getData' IMMUTABLE LANGUAGE java;
CREATE VIEW centros_votacion AS SELECT oracle.getData();


Cuarto: Invocando la vista

Sencillamente puede llamar la vista de la siguiente forma:


SELECT * FROM centros_votacion;

Cómo convertir archivos SHAPE a MySQL

Para convertir archivos SHAPE a MySQL debe utilizarse el comando shp2mysql de la siguiente forma:


$ shp2mysql -s 4326 -d shps_estado_yar/yar_poblaciones_font_point.shp yar_poblaciones_font_point camposer > mysql/yar_poblaciones_font_point.sql


Donde:
  • La opción -s específica el datum. Si no es especificado coloca -1 por omisión, luego, la mayoría de cartografía que se encuentra pública posee como datum el EPSG 4326 (WGS84).
  • El archivo .shp que desea transformar. Se coloca seguido de la opción -d
  • El nombre de la tabla
  • El nombre de la BD

Cómo convertir archivos SHAPE a PostgreSQL (PostGIS)

Para convertir archivos SHAPE a PostgreSQL (PostGIS) debe utilizarse el comando shp2pgsql de la siguiente forma:


$ shp2pgsql -s 4326 ~/Desktop/shp_yar/yar_estados_region.shp yar_estados_region > yar_estados_region.sql


Donde:
  • La opción -s específica el datum. Si no es especificado coloca -1 por omisión, luego, la mayoría de cartografía que se encuentra pública posee como datum el EPSG 4326 (WGS84).
  • El archivo .shp que desea transformar
  • El nombre del esquema, seguido de la tabla que se generará. En caso de no colocar esquema (formato esquema.tabla), el comando asume el esquema public
  • El nombre del archivo donde se desea enviar el SQL generado

Cómo crear y trabajar con procesos batch en Symfony 1.2

Aquí les dejo un ejemplo (Hola mundo!):


rodolfo@rcampos-laptop:/var/www/proy$ symfony generate:task pbatch:exec --use-database=false
>> task Creating "/var/www/proy/lib/tas...chExecTask.class.php" task file
rodolfo@rcampos-laptop:/var/www/proy$ vi lib/task/pbatchExecTask.class.php
rodolfo@rcampos-laptop:/var/www/proy$ symfony pbatch:exec
Hola mundo
rodolfo@rcampos-laptop:/var/www/proy$

Cómo exportar e importar bases de datos Oracle

A continuación se explica el método de exportación e importación utilizando sqlplus.

Primero que nada debe chequear que la variable ORACLE_HOME esté seteada y sería bueno incluir los binarios de Oracle en el PATH. Por ejemplo:


export ORACLE_HOME=/usr/lib/oracle/xe/app/oracle/product/10.2.0/server
export PATH=$PATH:/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin


Luego, al ejecutar el sqlplus la conexión deberá ser de la forma:


$ sqlplus USUARIO/PASSWORD@IP_BD/SERVICE_NAME


Para generar el respaldo (export):


SQL> host exp USUARIO/PASSWORD owner=DUEÑO_BD file=NOMBRE_ARCHIVO.dmp


Para restaurar el respaldo (import):


SQL> host imp USUARIO/PASSWORD fromuser=DUEÑO_BD file=NOMBRE_ARCHIVO.dmp touser=USUARIO;


En caso de que deba borrarse el usuario de la base de datos antes de restaurar el respaldo (si hay tablas preexistentes). Esto debe hacerse conectado como otro usuario:


SQL> drop user USUARIO casade;
SQL> create user USUARIO identified by "PASSWORD" default tablespace TABLESPACE quota unlimited on TABLESPACE;
SQL> grant connect,resource to USUARIO;

Cómo copiar toda una carpeta vía HTTP usando WGET (Ideal para copiar carpetas de imágenes de sitios Web)

Aquí les dejo el comando...

wget -r -np -A png -l 1 http://openlayers.org/dev/img/

  • -r Copia de forma recursiva
  • -l 1 Para seguir sólo un nivel de profundidad
  • -np No incluir carpetas padre (no parent folders)
  • -A png Para sólo descargar archivos PNG

Cómo borrar tablas de un esquema en Oracle

Para borrar todas las tablas de un esquema Oracle:

SELECT 'drop table '||table_name||' cascade constraints;' FROM user_tables;

Cómo insertar fechas en Oracle con formato variable

Para insertar fechas en Oracle con formato variable se debe utilizar la función to_date, por ejemplo:


INSERT INTO table_name
(date_field)
VALUES
(to_date('2003/05/03 21:02:44', 'yyyy/mm/dd hh24:mi:ss'));

Cómo migrar una BD de MySQL a Oracle

Esto me dió muchísimos problemas, hasta que por fín!!! Una alternativa para migrar BDs de MySQL a Oracle.

La mejor manera hasta la fecha y comprobada, es:

  1. Descargar el Oracle SQL Developer
  2. Descargar el Driver JDBC de MySQL
  3. Crear un usuario en Oracle a donde se migrarán los datos (full permisos)
  4. Logearse, por ejemplo a través del apex, como SYS o SYSTEM, y agregar el permiso RESOURCE con la opción ADMIN (mostrado abajo).
  5. Luego de haber agregado privilegios de admin al usuario Oracle, en las preferencias de SQL Developer debe agregar el driver JDBC de MySQL.
  6. Luego en la pestaña de Migrar datos de SQL Developer seleccionar Migración rápida y listo!

GRANT resource TO NOMBRE_USUARIO WITH admin OPTION;

NOTA: En mi caso tuve muchos problemas cuando tenía otras BDs en MySQL, por ello las borre todas, prevío respaldo utilizando:

mysqldump [opciones] --all-databases

Eeeeso es todo amigos...

Cómo crear usuarios en MySQL (rápidamente)

Para crear usuarios en MySQL debe ejecutar el siguiente comando en consola:


mysql> GRANT ALL privileges ON *.* TO 'u_pmos'@'localhost' IDENTIFIED BY 'u_pmos123';


Este comando creará un usuario llamado u_pmos (con contraseña u_pmos123) que se podrá conectar desde localhost y tener acceso a todas las bases de datos y tablas.

Librería de PHP para enviar correos (phpmailer)

Para enviar los correos desde php debemos instalar y utilizar la librería phpmailer.

Para instalar la librería deben copiar los siguientes archivos: class.phpmailer.php, class.smtp.php y phpmailer.lang-es.php a la carpeta indicada en la directiva include_path (generalmente /usr/share/php) de su archivo de configuración de php (php.ini).

El proyecto está disponible acá: http://sourceforge.net/projects/phpmailer/

NOTA: deben estar seguros de que la directiva no se encuentre comentada (los comentarios en estos archivos de configuración se realizan con un punto y coma ";" al comienzo de la línea).

Shell script para capturar datos de un puerto serial en Linux

A continuación presento un pequeño script que captura datos del puerto serial de una máquina con Linux y lo recibido es enviado a un archivo PHP que se encarga del procesamiento.

Esto fue utilizado para extraer datos de un tarificador de llamadas Samsung y enviarlas a un script PHP que almacena los datos en BD.


#!/bin/bash

RUTA_PROCESADOR=/var/www/Captura
RUTA_PS=/dev/ttyS0 #Puerto Serial

CONF_VELOCIDAD="4800"
CONF_NUMERO_BITS_TRAMA="7"
CONF_OPCIONES="-parenb"

#Configurando puerto serial para lectura
stty $CONF_VELOCIDA -F $RUTA_PS cs$CONF_NUMERO_BITS_TRAMA $CONF_OPCIONES

#Capturando data
cat $RUTA_PS | while read line; do php $RUTA_PROCESADOR/controlador_llamada.php "${line}" && echo ${line}; done >> $RUTA_PROCESADOR/traza.log &


El script configura primero el puerto a través del comando stty y luego con un simple cat sobre el archivo configurado (RUTA_PROCESADOR) se extraen los datos. Cada una de las líneas capturadas ${line} es enviada al script $RUTA_PROCESADOR/controlador_llamada.php.

Shell script para saber si tenemos conexión a Internet

Para probar si una máquina tiene conectividad a internet puede utilizar el siguiente script:


#!/bin/bash

main()
{
ping -c 4 www.google.com > /dev/null
if [ "$?" -eq 0 ]
then
echo "Si hay internet";
else
echo "No hay internet";
fi
}

main


El código mostrado arriba hará 4 pings contra Google y si todo salé bien el comando retornará un 0 como estatus de salida (extraído con la variable $?). Luego, si las cosas salen mal retornará cualquier otro número mayor que 0. Se redirije la salida a /dev/null para no sacarla por pantalla o al correo del usuario dueño del proceso.

El script de arriba no funciona en redes donde se filtran paquetes ICMP. Debido a que estos filtros son habilitados comunmente podría agregarse la siguiente línea utilizando el comando wget.


#!/bin/bash

main()
{
wget www.yahoo.com > /dev/null
if [ "$?" -eq 0 ]
then
echo "Si hay internet";
else
echo "No hay internet";
fi
}

main

Creando un live CD con Debian

Para crear un CD autónomo (live cd) con Debian (versiones etch en adelante) utilizando DebianLive debe primero instalar el paquete live-helper (apt-get install live-helper). Ahora, para poder hacer esto deberá agregar la siguiente línea a su archivo de fuentes apt (/etc/apt/sources.list) y actualizar la lista de paquetes (apt-get update) :

deb http://www.backports.org/debian etch-backports main contrib non-free

Una vez instalado el paquete live-helper deberá crear una carpeta y dentro de ella configurar su CD utilizando el comando lh_config, por ejemplo:

lh_config -p gnome-desktop -a i386 --hostname mi-autocd --packages "apache2 php5" --username usuario --verbose --bootappend "locale=es_VE.UTF-8 keyb=es"

A continuación el detalle de cada opción:

  • -p gnome-desktop se utiliza para indicar el tipo de entorno gráfico, en este caso gnome pero podría ser: kde-desktop o xcfe-desktop. Al utilizar esta opción el entorno gráfico contendrá además OpenOffice, Evolution, Gimp, Juegos, Firefox, entre otros.

  • -a i386 se utiliza para indicar el tipo arquitectura.

  • --hostname se utiliza para indicar el nombre de la máquina (host) cuando se ejecute el CD.

  • --packages se utiliza para indicar los paquetes que serán instalados, adicional a los básicos del entorno.

  • --username se utiliza para indicar el nombre del usuario por omisión que tendrá el sistema.

  • --verbose se utiliza para indicar que muestre en pantalla el estatus de la configuración.

  • --bootappend se utiliza para indicar opciones adicionales a agregar en la etapa de bootstrapping, en este caso idioma español de Venezuela (es_VE) y teclado con distribución en español. En principio, para agregar configuración de teclas para latinoamérica se debe especificar keyb=la-latin1 pero aparentemente hay un bug con esto porque no agarraba la ñ y la @, como un problema de número de teclas en el teclado (aunque irónicamente al bootear encontraba configuración PC-intel con 105 teclas, lo cual es correcto).



Una vez configurado el entorno (lh_config), deberá ejecutar el comando de construcción (lh_build), el cual generará -entre otros- una carpeta llamada chroot donde podrá encontrar la estructura de directorios (/bin, /etc, /home/, etc) y el archivo binary.iso que podrá ejecutar con un emulador (como: qemu o !VirtualBox) o simplemente quemarlo en un CD para ejecutar el sistema al bootear por el.

Si desea hacer alguna modificación sobre la estructura de directorios, simplemente hágala, ejecute lh_clean binary y luego lh_binary para regenerar el archivo ISO.

Estos enlaces le serán de bastante ayuda a la hora de generar su propio CD:

  • http://wiki.debian.org/DebianLive Aquí encontrará todas las páginas que componen el WIKI, preste especial atención a las siguientes:


    • http://wiki.debian.org/DebianLive/Howto/ISO Configuración de un CD básico

    • http://wiki.debian.org/DebianLive/Examples Configuración avanzada (hacks) para crear CDs

    • http://wiki.debian.org/DebianLive/Howto/Custom_Artwork Configuración de arte para el CD (Ej. Splash Screen - .rle)

    • http://wiki.debian.org/DebianLive/FAQ Es realmente importante prestar atención a este FAQ, sobre todo a las siguientes secciones:


      • http://wiki.debian.org/DebianLive/FAQ#head-6d6195543173e073b0422bb6cf4627e1801858cb Para poder ver archivos estáticos (Ej. HTML) a través del Apache. Esto me dió reales dolores de cabeza.

      • http://wiki.debian.org/DebianLive/FAQ#head-b01328e3d5e76c7ca04f7266fc813079dd350520 Para personalizar un escritorio y arrastrar la configuración.

      • http://wiki.debian.org/DebianLive/FAQ#head-5d1006287fae61495ee4e050946a61cec6f3046d Para ejecutar scripts en tiempo de booteo, esto pensé que me serviría para modificar el archivo hosts (/etc/hosts) porque necesitaba hacer unos hosts virtuales con apache, pero termine solucionandolo agregandole un script a la carpeta /etc/rc2.d que copiara el contenido de un archivo temporal en el /etc/hosts.





En general hay que estar muy atento a las configuraciones que puedan hacerse directamente a través del comando lh_configure para evitar errores. Encontré que trabajar con DebianLive es muy poderoso, pero realmente existe poca documentación al respecto.