lunes, 29 de octubre de 2012
Los certificados de menos de 1024 bits e Internet Explorer
Si, otra entrada mas dedicada a microsoft. Hace unas semanas, una de nuestras aplicaciones, que está corriendo en un servidor https empezó a dar problemas.
No a todo el mundo, solo a unos cuantos. Ni siquiera a todos los que tenian Explorer 9, tambien algunos con Explorer 8. Y otra gente funcionaba bien.
El problema tal como lo veian los clientes era de lo mas curioso: iban a su página de login (http) desde donde se les redirigía a la página de login de verdad, ya por https, y en el camino el navegador se quedaba colgado. Ningun mensaje de error, ni en cliente ni en servidor.
Hoy, tras unos ratos intentando localizar el problema, finalmente lo hemos encontrado: Hace unos meses Microsoft lanzó un aviso sobre la inseguridad de los certificados de menos de 1024 bits y aparentemente en alguna de las actualizaciones de Windows Update liberaron el parche KB2661254.
Efectivamente, el certificado que tenia el servidor (autofirmado) era de 512 bits, aparentemente el valor por defecto cuando generé las claves, pero... hombre!, ¡no es para tomárselo asi!. Y al menos, podían dar un aviso de error indicando lo que estaba pasando. Lo de dejar frito el navegador sin pantallazo azul ni nada no está bien.
Asi que ya lo sabes: si te esta dando un problema de este tipo es probable que tu error sea el mismo que el nuestro, y no parece que este documentado por muchos sitios. Será que éramos los unicos que teníamos este tipo de certificado...
lunes, 22 de octubre de 2012
Trampas y trucos de GORM - Parte 1
¿Eres nuevo en Grails?. O ¿has tenido tu primera pesadilla con GORM?. Si es asi, tal vez te interese leer estas anotaciones de Peter Ledbrook traducidas. En ellas se intentará explicar no solo las peculiaridades que a veces nos hacen tener errores sino tambien porqué GORM se comporta de esa forma.
Supongo que al menos ya sabrás que GORM es la libreria de acceso a base de datos que se utiliza con Grails. Está basada en el que probablemente es el ORM más popular, Hibernate. Como ya puedes suponer, Hibernate es una herramiente muy potente y flexible, pero usarla tiene su coste, y muchos de los problemas que suelen tener los usuarios de GORM tienen su origen en la forma en que funciona Hibernate. GORM intenta ocultar los detalles de la implementación de la mejor forma posible, pero a veces hay cosas que no funcionan tan bien como uno desearía.
En esta anotación describiremos las bases de persistencia de objetos en una base de datos. Suena sencillo, pero incluso en cosas tan aparentemente simples GORM tal vez no funcione de la forma en que tu lo esperas.
Cuando llamo a save(), quiero decir save!: guárdalo!
Los problemas guardando instancias de clases de dominio son con seguridad los primeros con los que se encontrará un desarrollador. Puede suceder que te encuentres en el caso de "lo he guardado, asi que ¿porqué no está en la base de datos?". Si te sirve de consuelo, a todos nos ha pasado. Pero ¿por qué sucede?. Puede haber un par de posibilidades.
No te olvides de la validación!
Cada vez que llamas al método save() para guardar una instacia de una clase de dominio, Grails la valida usando las constraints que has definido. Si algun valor viola estas constraints, grails no guardará en registro en la base de datos y se adjuntarán los errores correspondientes en tu instancia. El problema es que este proceso es silencioso: no te darás cuenta de lo que ha pasado a no ser que verifiques el valor de vuelta de save() o hagas una llamada al método hasErrors().
Cuando estas asociando tu instancia de la clase de dominio con los datos que ha introducido un usuario por pantalla, normalmente este es el comportamiento deseado: no es una sorpresa que los usuarios se equivoquen al introducir los datos o que estos no sigan el comportamiento que has definido, asi que hacer saltar una Exception en un caso asi, simplemente no parece apropiado. Es mejor verificar lo que ha pasado en la llamada al método save() para informar al usuario y que pueda actuar en consecuencia. El método save() devolverá null si ha habido algun problema, o la instancia de la clase en caso de que todo haya salido bien.
def book = new Book(params)
if (!book.save()) {
// Fallo! Mostrar errores al usuario
...
}
Por otro lado, cuando estas introduciendo datos de prueba en la clase de BootStrap o en la consola Grails, normalmente esperaras que los datos sean correctos (¡los estas metiendo tu!), asi que si hay algún fallo de validación es porque has metido la pata. En este caso, seguramente preferirías no complicarte verificando el valor de cada llamada a save() y que si tienes un error Grails te avise con una Exception. No es el comportamiento por defecto, pero puedes usarlo de forma sencilla con el argumento failOnError de save():
book.save(failOnError: true)
Si insistes, incluso puedes hacer que este sea el comportamiento por defecto: simplemente asigna la propiedad grails.gorm.failOnError a true en grails-app/conf/Config.groovy. Y por cierto, no te olvides de que todas las propiedades de una clase de dominio tienen por defecto una constraint de nullable: false!
La sesión de Hibernate
En alguna ocasión extraña, te encontrarás el caso de salvar una instancia de tu clase sólo para descubrir que la siguiente consulta a base de datos no la encuentra, incluso aunque haya pasado todas las validaciones.
Esto puede ser a causa del funcionamiento de Hibernate por debajo, ya que Hibernate es un ORM basado en sesiones. Este es un punto importante y para sentirte cómodo con GORM deberías comprender perfectamente el impacto que esto puede tener en tus aplicaciones.
¿Que es una sesion?. Basicamente es un cache en memoria de objetos que van y vienen de la base de datos. Cuando guardas una instancia de una clase de dominio, está implícitamente unida a la sesión: esto es: se añado al caché y se convierte en un objeto manejado por hibernate. Pero se persiste a la base de datos en este punto! . El siguiente diagrama muestra este comportamiento:
Cuando guardas una instancia, está inmediatamente disponible para esa sesión, pero Hibernate puede decidir que prefiere persistir a base de datos mas tarde para optimizar el acceso a la base de datos. Normalmente no te darás cuenta de estas cosas porque Hibernate y Grails se encargan de ello, pero a veces sucederán estas cosas.
Como puedes imaginar, Grails te permite un cierto grado de control sobre estos casos. ¿Has visto código como este en algun ejemplo? :
book.save(flush: true)
Ese flush: true fuerza a Hibernate a persistir los cambios en la base de datos ahora mismo. Es lo que se llama hacer flush de la sesion.
Ahora. claro, estarás pensando que porqué no poner flush: true por todo todos lados. No lo hagas. Deja que Hibernate haga su trabajo y solo usa este recurso cuando necesites hacerlo, por ejemplo al final de un proceso de actualizacion batch o por lotes. Sólo deberias usarlo cuando no veas datos en la base de datos que deberían estar ahí. Ya se que parece un poco sistema de ensayo y error, pero el como funcione en tu caso dependerá de la implementacion de tu base de datos y de otros factores. Un caso donde probablemente sea muy util forzar la escritura a disco es cuando este interactuando con otra aplicación que acceda a la misma base de datos.
Y ahora que no quiero que guardes, ¿lo haces?
En el apartado anterior hemos visto que a veces una llamada al método save() no guarda los datos, al menos no instantaneamente. Pero considera ahora el caso inverso: objetos que se persisten en la base de datos sin su llamada a save() correspondiente. Si no te ha pasado nunca, te garantizo que antes o despues te pasará. ¿Porqué sucede?
Hibernate tiene el concepto de dirty-checking (N.del.T: podriamos traducirlo como verificación de datos que han cambiado desde que se leyeron o algo asi. Mejor lo dejo en inglés). Este comportamiento verifica que datos salieron de la base de datos, y si han cambiado en memoria, intenta escribirlos de vuelta. Como puede parecer -y lo es- un poco lioso, mejor lo vemos con un ejemplo: Supongamos la clase de domino Libro con un par de propiedades titulo y autor y el siguiente código en su clase controller:
def b = Book.findByAuthor(params.author)
b.title = b.title.reverse()
Fíjate en que no hay ninguna llamada a save(), pero cuando la petición haya finalizado te encontrarás con que el titulo está al reves en la base de datos. El cambio se ha persistido en la base de datos sin una llamada explicita a save(). Esto ha sucedido porque:
- El libro esta unido a la sesion (por haber sido recuperado por una query)
- La propiedad titulo es persistente (todas las propiedades lo son a no ser que las configures como transient)
- El valor de la propiedad ha cambiado cuando la sesion se cierra
Segundo: las clases de dominio son persistentes por defecto, asi que tienen una columna en la base de datos relacionada con cada propiedad que hayas definido para guardar sus valores. Pero puedes hacer que la propiedades sean transitorias añadiendolas la lista estatica transients , que se usa precisamente para no guardar esos valores en la base de datos.
Para terminar, hemos mencionado que los cambios se persisten si existe cuando se cierra la sesion. ¿Que quiere decir esto?. Que para hacer cualquier operacion con Hibernate tienes que tener abierta una sesion. Una vez que se cierra la sesion no puedes usarla para acceder a la base de datos. La sesion es flushed (forzada a escribirse en base de datos) al final de la accion de nuestro controlador (Grails automaticamente abre una sesion al principio de la peticion y la cierra al final)
¿Podemos evitar este comportamiento?. Claro que si. Una opcion es llamar nosotros a save() en nuestra instancia de clase de dominio: si alguna de las propiedades falla las validaciones, los cambios no persistirán. Por supuesto, aunque los datos cumplan con las validaciones puede que no querramos que persistan, y podemos llamar al método discard() en nuestra instancia de clase de dominio. Esta operación no restaura los valores originales, pero asegura que los nuevos no se guardan en la base de datos.
Hasta aqui tenemos una buena cantidad de información para ir digiriendo hasta la próxima entrada. La clave es comprender como la sesion de Hibernate puede afectar al comportamiento de tus clases de dominio. En las próximas anotaciones habrá mas información y ejemplos.
En general, se recomienda que siempre utilices save() para guardar tus objetos en lugar de fiarte del dirty-checking. Hace tu código mas claro tiene la ventaja de que tus cambios son primero validados y luego guardados. Tambien es muy recomendable verificar el valor de vuelta del método save() y utilizar el parámetro failOnError: true cuando estés dando de alta datos de prueba o en el bootstrap.
Si lo que has leido hasta aqui de GORM te ha intimidado, recupérate, no es para tanto. Hace que jugar con la base de datos se mas sencillo y divertido, y confío en que esta serie de artículos te sean de ayuda para solucionar los problemas que puedas ir encontrando.
Anotación original, de Peter Ledbrook: Gorm Gotchas - Part 1
Anotaciones relacionadas: Trampas y Trucos de GORM - Parte 0
Trampas y trucos de GORM - Parte 0
En las siguientes anotaciones voy a intentar traducir de forma mas o menos libre las excelentes entradas sobre GORM, el módulo de acceso a datos de Grails, escritas por Peter Ledbrook en el blog de Springsource Gorm Gotchas - Part 1, Gorm Gotchas - Part 2 y Gorm Gotchas - Part 3.
Mi motivación es por una parte puramente egoista: Estoy aprendiendo Groovy y Grails sin tener ningún conocimiento previo de Spring ni Hibernate, llegando directamente desde el Java del Siglo XX y con conocimientos básicos de base de datos ya que siempre me he dedicado a código Java (bueno, no siempre). Pero las aplicaciones que solemos hacer en mi empresa suelen tener un gran componente de base de datos, asi que es necesario manejar ciertas estructuras con soltura.
Por otra parte, hay bastante poca literatura clara en castellano (o no he sido capaz de encontrarla) sobre GORM. Esta mañana, siguiendo unos enlaces de la lista de Grails en castellano he llegado a estas 3 páginas de Peter Ledbrook y me están pareciendo tan claras en la forma de exponer los conceptos que voy a ver si soy capaz de traducirlas de forma un poco decente aunque no sea de forma literal. De esta forma, además de interiorizar yo mismo los conceptos, si resulta que sirven para alguien mas... pues mejor que mejor.
Pasen y lean.
Trampas y trucos de GORM - Parte 1
Trampas y trucos de GORM - Parte 2 (en preparación)
Trampas y trucos de GORM - Parte 3 (en preparación)
Mi motivación es por una parte puramente egoista: Estoy aprendiendo Groovy y Grails sin tener ningún conocimiento previo de Spring ni Hibernate, llegando directamente desde el Java del Siglo XX y con conocimientos básicos de base de datos ya que siempre me he dedicado a código Java (bueno, no siempre). Pero las aplicaciones que solemos hacer en mi empresa suelen tener un gran componente de base de datos, asi que es necesario manejar ciertas estructuras con soltura.
Por otra parte, hay bastante poca literatura clara en castellano (o no he sido capaz de encontrarla) sobre GORM. Esta mañana, siguiendo unos enlaces de la lista de Grails en castellano he llegado a estas 3 páginas de Peter Ledbrook y me están pareciendo tan claras en la forma de exponer los conceptos que voy a ver si soy capaz de traducirlas de forma un poco decente aunque no sea de forma literal. De esta forma, además de interiorizar yo mismo los conceptos, si resulta que sirven para alguien mas... pues mejor que mejor.
Pasen y lean.
Trampas y trucos de GORM - Parte 1
Trampas y trucos de GORM - Parte 2 (en preparación)
Trampas y trucos de GORM - Parte 3 (en preparación)
On a new road
On a new road era el nombre del blog que James Gosling, autor de Java entre otras cosas, tenia durante el tiempo que paso en Google tras abandonar Oracle.
Y es el nombre de esta anotación porque es exactamente como me siento desde hace algunos meses: En un nuevo camino. No porque haya cambiado de empresa, cosa que (toco madera) espero que no suceda en mucho tiempo. Pero si porque despues de mucho tiempo, tanto mi empresa como yo necesitamos un cambio.
Yo empecé con este cambio hace un par de años. Tras mucho tiempo de mantener mi sistema nervioso al ralentí de repente vi la luz. Si, al estilo de los Blues Brothers. O algo asi. En realidad podríamos decir que fue mas parecido a lo que contaba una vez Motorhead Lenny de que un dia recuperó la conciencia desnudo en una playa comiendo una lata de alubias con una navaja y se dió cuenta de que asi no podia seguir. Lo mio no llegó a tanto pero de repente tome conciencia de que habia cosas que cambiar. Y, entre otras cosas, empecé a correr. Nunca hubiera pensado que yo era capaz de correr 10Km, menos aún un 31 de Diciembre, pero el año pasado fui capaz de terminar la San Silvestre. Y ni siquiera fuí el ultimo.
Y los cambios no sólo eran necesarios en mi forma de hacer las cosas: tambien en mi empresa habia que hacer muchos cambios. Y, Dios, que fuerte es la primera ley de Newton, ya sabes:
Que complicado es hacer cambios incluso en una empresa de poco mas de 10 personas que llevan trabajando muchos años. La inercia lo es todo, pero cuando las cosas no marchan todo lo bien que a uno le gustaría y se intentan hacer cambios la tarea se vuelve imposible: a los humanos nos gusta la seguridad de lo conocido aunque racionalmente nos demos cuenta de que no es el camino adecuado.
Intenté aplicar pequeños cambios en el funcionamiento de la empresa y aunque sobre el papel con mis socios parecían cosas razonables (en especial muchas de las que Berto Pena cuenta en su blog y su libro), en el dia a dia cuesta infinito llevarlas a la práctica.
Y entonces, en Febrero de 2012, llegó el Spring IO. Y fúe como meter mi cabeza en una maquina centrifugadora. O algo asi. Yo iba a ver de que iba Spring, si merecia la pena darle una oportunidad en lugar de usar GWT, que es lo que estaba mirando en aquel momento para sustituir a nuestro viejo -mas de 13 años- y propietario sistema de programacion, LWAS.
Y dos días despues sali con la cabeza sin Spring pero llena de JSON, Groovy & Grails, Hibernate, Scrum, RabbitMQ, herramientas de Atlassian, MongoDB, Git... Habia conocido -sin saber quienes eran- a Peter Ledbrook, Graeme Rocher, Matt Raible y Adrian Colyer. Asistí a las magníficas conferencias (entre otras) de Thomas Lin y de Domingo Suarez. Y todo ese mundo que se abría ante mi, como programador, no podia dejarlo escapar.
Asi que aqui estoy. Empezando de nuevo. Como un pardillo en programación a mis cuarenta y tantos, tras 10 años dedicado sobre todo a sistemas y con la programación, lo que siempre me ha gustado, dejada bastante -nunca del todo- de lado durante estos años. Sin tener apenas ni idea de javascript, ni de patrones de diseño mas allá de donde la intuición me ha llevado. La de cosas que han pasado en programación a mi lado sin que apenas me enterara dentro de mi caja estanca...
Intentando cambiar la metodologia de trabajo de la empresa hacia algo parecido a Agilismo, usando herramientas como Jira o Confluence sin las cuales no se como hemos podido vivir hasta ahora. Intentando entender si Bamboo y la integración continua nos sirve realmente para algo. Intentando dar la vuelta al cerebro para saber si la programación orientada a test es la panacea. O hasta que punto merece la pena. Pegándonos con Git.
En este camino nos esta echando una mano la (magnifica) gente de Salenda con Alvaro a la cabeza. Y abriendo mucho las orejas en las reuniones en petit-comité del grupo de usuarios de Grails Madrid junto con mi compañero Borja, sin el que no podría estar avanzando a la velocidad (sea la que sea, todo es relativo) que estamos haciéndolo.
Que coño. Hacia años que no me sentía tan vivo. A por ello.
domingo, 21 de octubre de 2012
Caramba, que coincidencia
El viernes pasado tuve uno de los mayores problemas a los que me he enfrentado en los ultimos tiempos: toda la infraestructura de servidores de mi empresa se vino abajo por culpa de un fallo de conectividad entre los servidores y el NAS. Los de produccion, los de desarrollo y los de uso interno.
Contado así el origen del fallo parece que no deberia haber sido para tanto, pero déjame contarte que hace alrededor de año y medio cambié todos (en su momento unos 14) los servidores físicos que tenia por sólo 3, utilizando la virtualización de VMWare ESXi. La forma en que lo instalé tal vez no sea muy convencional, pero lo hice montando los servidores sin discos duros ahorrandome una pasta en discos, controladoras RAID y demas, e invirtiendo ese dinero en meter mas memoria (tampoco una pasada: 32 GB de RAM, nada comparable a los 29 Tb de RAM que Larry Ellison dice que hacen falta para que Oracle vaya fino fino) y arrancando los servidores con un pincho USB.
¿Sin discos?. ¿Donde están los ficheros de las maquinas virtuales, los datos y todo lo demás?: En un único NAS, un Thecus 7700 con 7 discos en RAID6 (para ser exactos, 6 discos + 1 en espera) al que acceden los 3 servidores por iSCSI.
El sistema me ha estado funcionando mejor que fantástico durante este año y pico. Ni un solo fallo, mejora de velocidad en todos los procesos, flexibilidad infinita a la hora de 'ampliar el hardware' de las maquinas virtuales (« venga, un par de Gb mas de RAM para este servidor que ahora le hace falta », o « como vamos a hacer procesos de calculo intensivo, le meto 4 cores mas a este servidor »). Tambien, en lugar de apretar los programas en los servidores existentes me puedo permitir el lujazo de meter un solo servidor para nuevos servicios (y algun dia contaré lo mucho que estamos cambiando en mi empresa en este sentido) y tener todo mucho mas controlado y separados por funcionalidades.
¡Que bonito todo!, ¿verdad?. Si: hasta que, como comentaba al principio, un error de conectividad en uno de los switches hace que los servidores físicos pierdan la conexión con el NAS... y todo se venga abajo. Para mas coña (aún estoy investigando el porqué) despues de la pérdida de conexion el Thecus decidió que ya que habia dejado de trabajar, se echaba una siestecita, y se quedo frito. Resultado: unas 7 horas de reconstruccion de RAID.
Asi que ahí andaba yo, el viernes por la noche levantando los sistemas. ¿Y que me encontré?:
¡Si!. ¡Oh casualidad!. 29 servidores Linux (Ubuntus v8, v10, v12. Fedoras 6, CentOS), dos de ellos con cosas tan delicadas a priori como puede ser Oracle. Incluso un Windows 2003 Server. Y 3 malditos Windows 2008. Cuando intentaba arrancarlos me aparecia la pantalla de aviso de que algo iba mal y que entrara en modo a prueba de fallos. En uno de ellos directamente pantallazo azul y reboot.
Entrando en modo de recuperación me pedia el DVD de instalación y al dárselo me decia que no encontraba disco de sistema y que le dijera donde estaban los drivers (pues hombre, si no los encuentras tu... ). Resultado: tuve que restaurar la copia de seguridad de las maquinas virtuales de la semana pasada. Afortunadamente no he sufrido perdida de datos importantes en estos servidores pero el tema ha llamado mucho mi atención.
¿Como puede ser que de 33 servidores, repartidos por distintos volúmenes iSCSI, en un mismo NAS sólo haya problemas graves con 3 que corren el mismo sistema operativo?. ¿Alguien de ciencias me puede decir las probabilidades de que suceda esto?
En los Linux, que cuando sucedió el problema estaban echando humo de gente trabajando con ellos, sólo en 5 de ellos hubo que ejecutar el comando fsck para comprobar el disco. En 2 ni siquiera fué a causa del problema sino porque llevaban mas de 400 dias sin apagarse, y cuando en el arranque de un Linux se detecta que un sistema de ficheros lleva mas de X dias sin verificarse, se fuerza el chequeo.
Tengo algunos clientes que usan SQLServer en sus servidores de producción asi que me veo obligado a tener acceso a esta base de datos (que, dicho sea de paso, funciona bastante bien). Afortunadamente estoy migrando esta infraestructura a Amazon AWS para no tener que mantenerla, y despues de los problemas de este fin de semana, mas aún.
Desde luego, si mi falta de confianza en Windows andaba por los suelos, esta experiencia ha sido la puntilla que me faltaba.
Suscribirse a:
Entradas (Atom)