jueves, noviembre 03, 2016

Sobre wildfly y jboss-cli

Hace mucho que no trabajaba con jboss y en esta ocasión me tocó ocupar su versión gratuita Wildfly,

Wildlfy y jboss tienen una consola con la cuál se puede hacer scripting, sin más el  siguiente script lo ocupé para generar un nuevo servidor por cada ambiente que era necesario crear desde jenkins

Ver el siguiente gist:


Solo falta agregar unas variables de ambiente y correr el job con la opción "build with parameters"

miércoles, junio 01, 2016

Autoscalar RDS postgresql, más o menos.



Una de las cosas más difíciles de auto escalar son las bases de datos, aws amazon nos da la opción de escalar horizontalmente una base de datos mediante read replicas, lamentablemente en el caso de postgresql solo nos deja crear 5 y no hay opción de hacer read replicas de las read replicas (Esto se puede hacer en mysql).

Una forma de seguir creciendo es promover una read replica a master y crear sus otras 5 read replicas, pero hay que implementar un mecanismo de sincronización entre las dos master.

La otra es empezar con pocas read replicas he irlas creando de acuerdo a la demanda, esta opción es buena pero no es rápida, se basaría más en predecir el tráfico antes de que llegue, lo malo es que crear una read replica es  lento  aproximadamente unos 20 min.

Un escenario es tener creadas las 5 read replicas y escalarlas verticalmente cambiando el tipo de clase de instancias. Esta solución también es lenta, unos 7 u 8 min. Una ventaja de esta solución es que podemos jugar con los costos y por ejemplo tener solo 2 read replcias grandes y otras 3 micro.

Para que esta opción funcione necesitamos una arquitectura parecida a esta:



En nuestro ejemplo necesitaremos lo siguiente:
1. Tener creado un rds master con una read replica
2. Tener configurado 2 instancias con pgboucer uno para apuntar a master y otro a readreplica
3. Tener configurado un loadbalancer con esas dos instancias.

La modificación de las clase y encender el pgbouncer lo realizaremos a través de lambdas, las lambdas que usaremos son upgrade_db_instance_class y add_read_replica_to_elb.


Necesitaremos crear 2 topicos de SNS, para atacharlos a los eventos, uno de cloudwatch que disparará el aumento de la read replica y otro al finalizar la modificación de la read replica.



Y crearemos dos suscripciones, cada uno a su respectivo lambda:


Crearemos una alerta y mandaremos la notificación al topico 80_percent_rds


Y crearemos un Event Suscriptions en el rds para apuntarlo al topico upgrade_rds





Habiendo hecho todo eso ya podemos empezar con nuestra prueba.






Ocuparemos una instancia para lanzar las pruebas, estas se harán con pgbench y lo podemos instalar de la siguiente manera.

$ sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" >> /etc/apt/sources.list.d/pgdg.list'
$ wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | sudo apt-key add -
$ sudo apt-get update
$ sudo apt-get install postgresql-contrib

Ahora meteremos datos a la instancia:
$ pgbench -h hgmigueldb.comvkfys9x22.us-east-1.rds.amazonaws.com -p 5432 -Uhgmiguel -i -s 300 hgmigueldb

Y así correremos las pruebas:
$pgbench -h internal-pgbouncer-elb-592002074.us-east-1.elb.amazonaws.com -p 6432 -Uhgmiguel -c 64 -j 4 -T 900 -C -S hgmigueldb

Como ven ocupamos muchas cosas del entorno de aws, SNS, Lambdas, RDS, ELB, y Cloudwatch para poder armar esta arquitectura. Llega a ser abrumante la cantidad de servicios que hay en amazon pero conocerlos todos nos ayuda a crear mejores soluciones.

martes, noviembre 11, 2014

groovy dinámico

Los closures en groovy son muy utilizados, pero transformar metodos a closures no tanto, hay muchas ventajas como poder pasarlos como parametros de funciones o como valores en un mapa, para esto se ocupa el operador (.&)

13   def dynamicMethods = [[regex:"hasPermission(.*)", method:this.&hasPermission],
14   [regex:"create(.*)Permission", method:this.&createPermission]]


En este caso estamos convirtiendo el método hasPermission() y createPermission() en un closure y pasandoselo a un mapa, el metodo puede ser llamado como se muestra en la línea 21.

17   def methodMissing(String name, args) {
18   | def method = dynamicMethods.find { name =~ it.regex}
19   | if(method) {
20   | | def match = name =~ method.regex
21   | | return method.method(match[0][1], * args)
22   | } else
23   | | throw new MissingMethodException(name, DemoDynamic , args)
24   }
25 
26 }

Ocupando una expresión regular y methodMissing podemos mandar a llamar dinámicamente el método que vive en el mapa.

32 assert demo.hasPermissionHgmiguel("write")
33 assert !demo.hasPermissionOtros("write")

Dejo un Gist como ejemplo de lo que quiero explicar:

lunes, mayo 26, 2014

Eliminar switch

Hace mucho que no programo en java o algo parecido, últimamente hago mucho groovy y estoy aprendiendo clojure, pero bueno, revisando código en el trabajo me topé con una estructura switch, y de inmediato llamo mi atención:


  List<Role> findInviteRoles() {
    List roles = []
    def authorities = springSecurityService.getAuthentication().authorities
    authorities.each {role ->
      switch (role){
        case 'ROLE_ROOT':
          roles += ['ROLE_ROOT', 'ROLE_ADMIN']
          break
        case 'ROLE_ADMIN':
          roles += ['ROLE_ADMIN']
          break
        case 'ROLE_1':
          roles += ['ROLE_2']
          break
      }
    }
    Role.where {
      authority in roles.unique()
    }.list()
  }


A lo cual me pareció que el switch iba sobrado y decidimos hacer un refactor. Se puede ver que ahora están separados los datos de la lógica, lo cuál en algunos casos facilita la mantenibilidad del código.

 List<Role> findInviteRoles() {
    List roles = []
    def permisos = ['ROLE_ROOT':['ROLE_ROOT', 'ROLE_ADMIN'], 
                    'ROLE_ADMIN':['ROLE_ADMIN'], 
                    'ROLE_1':['ROLE_2']]
    def authorities = springSecurityService.getAuthentication().authorities
    roles = authorities.collect {
      permisos."${it}"
    }.flatten().unique()
    Role.where {
      authority in roles
    }.list()
  }

A mi punto de vista queda más limpio y claro el objetivo del collect que del switch. Dejo la prueba unitaria.
  @Unroll
  def "test list granted invite roles with #userRole and result #listResult"() {
    setup: "mockering"
    SpringSecurityService.metaClass.getAuthentication = { [authorities: [userRole]] }
    def springSecurityService = Mock(SpringSecurityService)
    service.springSecurityService = springSecurityService

    systemRoles.each {
      def role = new Role(authority: it)
      role.save validate: false
    }

    when:
    def list = service.findInviteRoles()

    then:
    list?.authority == listResult

    where:
    userRole       | systemRoles                                                || listResult
    'ROLE_ROOT'    | ['ROLE_ADMIN', 'ROLE_ROOT', 'ROLE_GARBAGE']                || ['ROLE_ROOT', 'ROLE_ADMIN']
    'ROLE_ADMIN'   | ['ROLE_ADMIN', 'ROLE_ROOT', 'ROLE_GARBAGE']                || ['ROLE_ADMIN']
    'ROLE_1'       | ['ROLE_ADMIN', 'ROLE_ROOT', 'ROLE_GARBAGE', 'ROLE_2']      || ['ROLE_2']
    'ROLE_2'       | ['ROLE_ADMIN', 'ROLE_ROOT', 'ROLE_GARBAGE', 'ROLE_2']      || []
  }

miércoles, marzo 19, 2014

Métrica C.R.A.P. con grails


Qué es el anti patrón de riezgo de cambio (Change Risk Anti-Patterns C.R.A.P)?
es un método para analizar y predecir la cantidad de esfuerzo, trabajo y tiempo requerido para mantener la base de código existente. La fórmula de C.R.A.P. es la siguiente:

C.R.A.P.(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)

Donde comp(m) es la complejidad ciclomática del método m y cov(m) es la cobertura de pruebas del método m.

Más información  aqui:

Al intentar configurar CRAP para grails me topé con que no pude utilizar gmetrics, le di muchas vueltas hasta que lo abandoné, leyendo sobre métricas me topé con esta presentación y ahí me di cuenta de que codenarc ya contiene a CRAP entre sus reglas. He aquí como lo configuré:




buildconfig.groovy
 25 grails.project.dependency.resolution = {
 54 
 55   dependencies {
 66     compile 'org.gmetrics:GMetrics:0.6'
 69   }
 70 
 71   plugins {
 85     compile ':codenarc:0.20'
 99   }
100 }
101 
110 
111 codenarc.reports = {
116   MyHtmlReport('html') {
117     outputFile = 'target/CodeNarcReport.html'
118     title = 'Violations Report'
119   }
120 }
121 
122 codenarc.propertiesFile='grails-app/conf/codenarc.properties'
123 codenarc.ruleSetFiles = "rulesets/basic.xml,rulesets/exceptions.xml, rulesets/imports.xml,rulesets/grails.xml, rulesets/unused.xml, rulesets/size.xml, rulesets/concurrency.xml,rulesets/convention.xml,rulesets/design.xml,rulesets/groovyism.xml,rulesets/imports.xml,rulesets/logging.xml"
124 

codenarc.properties
 1 GrailsPublicControllerMethod.enabled=false
 2 CatchException.enabled=false
 3 CatchThrowable.enabled=false
 4 ThrowException.enabled=false
 5 ThrowRuntimeException.enabled=false
 6 GrailsStatelessService.enabled=false
 7 NestedBlockDepth.maxNestedBlockDepth=3
 8 CrapMetric.enabled=true
 9 CrapMetric.coberturaXmlFile=file:target/test-reports/cobertura/coverage.xml

Ahora solo basta ejecutar:
grails test-app -unit -coverage -xml
grails codenarc

Como resultado tendremos más violaciones a las reglas pero seguro ayuda a mejorar en algo.

➥ ItemGroupsController.groovy

Rule NamePriorityLine #Source Line / Message
CrapMetric276
[SRC]def update() {
[MSG]Violation in class com.winbits.api.catalog.controllers.ItemGroupsController. The CRAP score for method [update] is [90.0]


El límite está puesto a 30 como máximo, este método tiene un índice de 90 lo cual nos indica que esta muy crapy, para poder reducir el índice se puede hacer un refactor para reducir su complejidad o aumentar sus pruebas automatizadas, claro que si se hace un refactor primero se tienen que hacer las pruebas para que sea seguro hacerlo :-)





domingo, enero 20, 2013

Capcom SNES jostick

Hace rato que tengo un botón hecho con arduino, este botón hace que vim cambie de modo comando a modo inserción. Un amigo  vio como lo ocupaba y se le ocurrió la idea de transformar un control capcom power stick para el snes y pasarlo a usb para poder utilizarlo como un controlador para Traktor.


He aquí como se transformó:



Después de un tiempo de observación noté que una vez que le pasas tierra o corriente a la placa toda esta queda con electricidad, lo que nos facilita la tarea de cablear y ver como funciona, el integrado que hace que funcione con el snes no lo ocupamos para nada, y creo que sería mejor desoldarlo en algún momento. Para estar seguros ayuda mucho tener un multimetro.


Así que fue cosa de soldar un pequeño dispositivo para poder conectarla a la corriente del arduino y empezar a jugar un poco con las conexiones, después fue ir soldando las terminales de los botones y conectarlas directo a una terminal del arduino.



El primer intento lo hice con el arduino pro ethernet de sparkfun, pero para que funcionará necesitaría de otro programa que emulará los tecladazos debido a que este arduino no es reconocido como una interfaz usb hid, así que decidí comprar un arduino leonardo para este caso.




El código puede obtenerse de aqui, esta es la parte que lee los botones, utilicé la variable arrayLettersBits para pasarle la tecla que quería que se presionara:

  //Letras a pulsar en el teclado
  const String arrayLettersBits = "arbxyl512346";

  for (int i = 2; i <= maxButtonPin; i++) {
    buttonState = digitalRead(i);
    if (buttonState != HIGH) {
      Keyboard.press(arrayLettersBits[i-2]);
    } else {
        Keyboard.release(arrayLettersBits[i-2]);
    }
    
  }

Esta parte es la que lee la palanca, aqui utilicé un pequeño hack, puesto que los switches del Jostick me regresaban aveces 0.1v o algo así y el arduino lo estaba detectando como HIGH, es por esto que utilicé analogRead en vez de digitalRead.

for (int i = jostikInitPin; i <= jostikEndPin; i++) {
    buttonState = analogRead(i);
    if (buttonState == 1023.00) {
      switch(i) {
        case 0:
          delay(5);
          buttonState = analogRead(i);
          if (buttonState == 1023.00) {
            Keyboard.press(KEY_RIGHT_ARROW);
            jostickBits[i-jostikInitPin]='0';
          }
          break;
        case 1:
// Más código similar aqui
      }
    } else {
      switch(i) {
        case 0:
          Keyboard.release(KEY_RIGHT_ARROW);
          
          break;
        case 1:     
// Más código similar aqui
      }      
    }

Al final lo terminé probando con un emulador de SNES y un juego de street fighter.

Pero el verdadero uso será así:

lunes, octubre 22, 2012

namedqueries con left join

Una de las funciones que más me gustan de gorm es la de namedQueries, que no son otra cosa que queries que viven dentro de las clases de dominio a los cuales se les puede aplicar metodos como list, count, y pasarles argumentos, etc.

Supongamos que tenemos la siguiente estructura de BD

Persona -> Ocupacion -> Categoria

Y que queremos contar el numero de personas por categoría, incluyendo aquellas que no tengan ocupacion (ocupacion = null), el problema es que para llegar a la solución necesitamos de dos left join con sql, recordando que los nameqQueries utilizan la misma nomenclatura que los criteria builder se nos ocurre que hay que ocupar CriteriaSpecification.LEFT_JOIN.

El siguiente namedQuerie dentro de persona hará nos solucionará el problema

groupByCategoria {params ->
            ocupacion(CriteriaSpecification.LEFT_JOIN) {
                categoria(CriteriaSpecification.LEFT_JOIN) { }
                projections {
                        groupProperty("categoria")
                        rowCount("total")
                }
            }
        }


Y ya podremos ocuparlo de la siguiente manera:

Persona.groupByCategoria.list()

Esto generará una lista como la siguiente:
[Categoria : 1:3, Categoria : 2:1, null:1]


Creo que nunca me va a gustar hibernate, sobre todo porque le quita todo el poder del lenguaje sql, peor bueno, cuando no hay otra solución más vale aprender bien la tecnología usada.

domingo, agosto 19, 2012

Sobre grails y plugins


Por curiosas razones (ocupar cherokee como proxy server y no tener un módulo de AJP) tuvimos un bug con recursos protegidos por SSL, en concreto tomcat nos regresaba recursos con http en vez de https...

La primera aproximación fue excluir los recursos que daban problemas, lo cual no iba a prevenir que esto siguiera pasando, en la configuración se detalla como hacerlo, en concreto hay que usar grails.resources.adhoc.excludes para excluir los recursos que causan problemas.

Cuando volvió a producirse el error se investigó mejor y se analizó el código del plugin de  resurces, de lo cual se llego a un @todo que nos daba problemas... 


○ → find . -name "*.groovy"  | xargs grep -i todo | awk -F'/' '{out=$8; for(i=9;i<=NF;i++){out=out" "$i};print out}'

ResourceTagLib.groovy:               @todo where a module resource is bundled, need to satisfy deps of all resources in the bundle first!
ResourceTagLib.groovy:     * @todo Later, we implement ESP hooks here and add scope="user" or scope="shared"
ResourceTagLib.groovy:        def baseUrl = ''    @todo get from config
ResourceTagLib.groovy:               @todo do we need to toggle http https here based on current request protocol?
ResourceTagLib.groovy:     * @todo this currently won't work for absolute="true" invocations, it should just passthrough these

Navegando por las entrañables aguas del código fuente ajeno llegamos a la función que nos daba el error redirectToActualUrl, la solución fácil y para no esperar una actualización en el plugin fue  sustituir la función por medio de metaprogramación en groovy.


        ResourceProcessor.metaClass.redirectToActualUrl = {ResourceMeta res, request, response ->
            //... Codigo ...
            def u = (grailsApplication.config.grails.serverURL? grailsApplication.config.grails.serverURL.toString() : request.contextPath) + staticUrlPrefix+res.linkUrl
            //... Codigo ...

        }


Como moraleja no hay que confiar mucho en plugins ajenos, hay por todos lados @todo, uno de los que más me afectan son las pruebas unitarias, no toda la funcionalidad de GORM esta integrada, casi siempre se termina haciendo pruebas de integración para solventar este problema. Aún así grails es una herramienta excelente para programar aplicaciones web, no regresaría a java + frameworks para esto...


sábado, agosto 18, 2012

ssl y cherokee

Nadie va a negar que godaddy vende certificados muy baratos en comparación con verisign, así que  para empresas de nueva creación godaddy es la opción... Y por barato los problemas no tardan en aparecer.

Nuestro certificado marcó problemas con dispositivos móviles. En concreto no reconocía a la autoridad certificadora. Luego de investigar y de no tener idea en que parte había hecho las cosas mal descubrí en el siguiente blog la solución al problema... Y era tan simple como concatenar el archivo gd_bundle al certificado:

$cat gd_bundle.crt >> dominio.com.crt

powered by cherokee

Dejo la nota original.
http://fluidsurveys.com/cherokee-web-server-ssl-setup/

After trying many things, and contacting godaddy, who told me they did not support Cherokee, I finally managed to figure out how to get it to work. The answer is pretty simple, if you follow the rest of the directions about setting up SSL with Cherokee, pointing your virtual server to the correct ssl certificate (Ours was fluidsurveys.com.crt) and the proper key (fluidsurveys.com.key) there was no place to input the gd_bundle.crt (The inermediate certificate package that godaddy provided us). The solution is to combine your site certificate (fluidsurveys.com.key) with your bundle certificate, root certificate, or intermediate certificates. To do this, simply make a backup of your site certificate (fluidsurveys.com.crt), then cat the intermediate bundle with the original site certificate.  “cat gd_bundle.crt >> fluidsurveys.com.crt” This should now solve your issue with IE6 not recognizing the issuer of your SSL certificate.



miércoles, abril 11, 2012

Sobre los archivos .desktop

Tengo localizado mi linux/gnu/debian/Gnome en el idioma gabacho, pero hay una herramienta que hoy ocupo mucho y que es importante que este en mi idioma natal, español de México, por qué, si no entiendo algo podría cometer una equivocacion, este programa es homebank

Bueno, la primera tarea fue hacer que la aplicación se ejecutara al principio, cuando se inicia sesión, no encontré nada fácil en gnome shell, así que googleando se llega a la solución:

Meter un archivo .desktop en ~/.config/autostart/

Para encontrar el archivo .desktop de homebank realicé la siguiente búsqueda:
chicuace1 in ~/
○ → find /usr/share/ -name "homebank*desktop"
/usr/share/app-install/desktop/homebank.desktop

Una vez encontrado el archivo lo copiamos a la ruta de autostart y listo, volvemos ha entrar a la sesión y se ejecuta automáticamente. Hasta ahí todo bien, pero se sigue ejecutando con el locale de US.

Para cambiar el locale necesitamos saber si tenemos el locale que queremos, para eso ejecutamos:

chicuace1 in ~/
○ → locale -a
C
C.UTF-8
en_US.utf8
es_MX.utf8
POSIX


Y ahí esta, el que me interesa es es_MX.utf8, en caso de no hayarlo en mi debian debo de hacer dpkg-reconfigure locales, para otras distribuciones habrá un comando similar. Ahora si ejecutamos lo siguiente tendremos nuestra aplicación traducida al español

chicuace1 in ~/bin
○ → LANG=es_MX.utf8 homebank


Bien, no encontré en la especificación de freedesktop una manera de modificar el LANG, así que no me quedó de otra que crear un sh con esa instrucción :

chicuace1 in ~/bin
○ → echo "LANG=es_MX.utf8 homebank" > homebank.sh && chmod a+x homebank.sh

Una vez probado ese script hay que modificar nuestro ~/.config/autostart/homebank.desktop sustituyendo Exec=homebank %F por Exec=/home/usuario/bin/homebank.sh %F

Y ahora ya tendremos nuestra aplicacion localizada al español y ejecutandoce cada inicio de sesión.

P.D. si ven este símbolo ○ → en mi shell es porque ocupo bash-it, les recomiendo ampliamente ocuparlo, muchos otros recomiendan zsh...